GHSA-34fj-mwm6-fjfg
SiYuan: The session-cookie signing key (Conf.CookieKey) is returned to anonymous readers by /api/system/getConf
Quick fix
GHSA-34fj-mwm6-fjfg — github.com/siyuan-note/siyuan/kernel: upgrade to the fixed version with the command below.
go get github.com/siyuan-note/siyuan/kernel@v0.0.0-20260725123945-77421530be4aDetails
**CVE:** This vulnerability corresponds to [CVE-2026-72794](https://nvd.nist.gov/vuln/detail/CVE-2026-72794).
### Summary
`/api/system/getConf` returns `Conf.CookieKey`, the key used to sign the server's session cookies in its response body. The endpoint is registered with `CheckAuth` only, so the field reaches the publish `RoleReader` token and the anonymous account when `Publish.Auth.Enable` is `false`.
The configuration-export endpoint in the same file strips this exact field before returning config, so the project already treats it as secret. The reader-facing masking path does not.
### Details
| Item | Detail | |---|---| | Route | `kernel/api/router.go:70` `POST /api/system/getConf` → `model.CheckAuth` → `getConf` | | Middleware | `CheckAuth` only — no `CheckReadonly`, no `CheckAdminRole` | | Leaked field | `AppConf.CookieKey`, serialized as `cookieKey` | | Purpose of the field | Signing key for the `siyuan` session cookie |
**The field survives every stage of the masking chain.** `getConf` masks through `GetMaskedConf()` → `HideConfSecret()` (non-administrators) → `FilterConfByPublishIgnore()` (readers) → the browser-side System-path strip. `CookieKey` is removed by none of them:
- `GetMaskedConf` masks `UserData`, `MCPOAuth` and `AccessAuthCode` only. - `HideConfSecret` nulls `AI`, `Api`, `Flashcard`, `ServerAddrs`, `Publish`, `Repo`, `Sync`, `Secrets`, `Variables` and the System paths. It contains no reference to `CookieKey`. - `FilterConfByPublishIgnore` touches `UILayout` only. - The browser-side strip removes System paths only.
**The key is live, not vestigial.** It is passed straight into the session store at startup:
``` cli/cmd/serve.go:67 go server.Serve(false, model.Conf.CookieKey) kernel/server/serve.go:152 sessionStore = cookie.NewStore([]byte(cookieKey)) kernel/server/serve.go:159 ginServer.Use(sessions.Sessions("siyuan", sessionStore)) ```
`gin-contrib/sessions/cookie.NewStore` constructed with a single key uses that key as the `gorilla/securecookie` HMAC key. The `siyuan` session cookie is therefore signed with the value the endpoint hands out. An attacker holding it can mint and modify session cookies that the server accepts as authentic.
**Guarded sibling, in the same file.** `exportConf` (`kernel/api/system.go:299`) clones the configuration before returning it and explicitly clears both secrets:
``` kernel/api/system.go:360 clonedConf.CookieKey = "" clonedConf.NotebookCrypto = nil ```
The project has already classified `CookieKey` as a value that must not leave the server. The `getConf` masking path omits the same field.
**Ceiling is environment-dependent, floor is not.** Escalating a forged session to administrator additionally requires the forged `SessionData` to carry the matching `AccessAuthCode`, which `GetMaskedConf` does mask or the instance to have no access-auth code configured, which is a common deployment. The unconditional impact, present on every instance, is the disclosure of a persistent cryptographic secret to an unauthenticated party together with the cookie-forgery capability that follows from it. Rotating the key invalidates all existing sessions, so this is not a secret that can be quietly refreshed.
### Proof of Concept
Precondition: publish mode enabled (default port 6808); anonymous when `Publish.Auth.Enable` is `false`, otherwise any publish reader account.
``` POST http://127.0.0.1:6808/api/system/getConf {}
→ 200 The response body's conf object contains a cookieKey field holding the server's session-signing key in cleartext. ```
Differential check against the endpoint that does strip it:
``` POST http://127.0.0.1:6808/api/system/exportConf → cookieKey is empty, notebookCrypto is null ```
The same value is withheld by one endpoint and returned by the other.
### Impact
An anonymous reader in publish mode or any publish `RoleReader` obtains the server's session-cookie signing key. This is a persistent cryptographic secret whose disclosure cannot be remediated without invalidating every active session. Possession of the key permits forging and tampering with `siyuan` session cookies that the server will validate as authentic. On instances with no access-auth code configured, or where a forged session's contents otherwise satisfy the server's checks, this extends to authenticating as a privileged user.
### Suggested fix
Clear `CookieKey` in `HideConfSecret` for all non-administrator responses. The more durable fix is to route non-administrator `getConf` through the `exportConf` cloner, which already handles `CookieKey`, `NotebookCrypto`, `Account`, `Stat`, `System.ID`, `Export.PandocBin` and the AI keys replacing the current blocklist, which fails open on every field nobody thought to add, with the allowlist-style cloner the project already maintains.
Are you affected?
Enter the version of the package you're using.
Affected packages
0Fixed in: 0.0.0-20260725123945-77421530be4ago get github.com/siyuan-note/siyuan/kernel@v0.0.0-20260725123945-77421530be4aReferences
- https://github.com/siyuan-note/siyuan/security/advisories/GHSA-34fj-mwm6-fjfg[WEB]
- https://nvd.nist.gov/vuln/detail/CVE-2026-72794[ADVISORY]
- https://github.com/siyuan-note/siyuan/commit/77421530be4ab1f43310d0f50fbab05d16c38675[WEB]
- https://github.com/siyuan-note/siyuan[PACKAGE]
- https://www.vulncheck.com/advisories/siyuan-before-session-cookie-key-disclosure-via-getconf[WEB]