{"id":"CVE-2026-72794","aliases":["GHSA-34fj-mwm6-fjfg","GO-2026-6420"],"title":"SiYuan: The session-cookie signing key (Conf.CookieKey) is returned to anonymous readers by /api/system/getConf","summary":"SiYuan: The session-cookie signing key (Conf.CookieKey) is returned to anonymous readers by /api/system/getConf","severity":"high","cvss":8.6,"cvssVector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N","vendor":"siyuan-note","product":"github.com/siyuan-note/siyuan/kernel","ecosystem":"go","affected":["github.com/siyuan-note/siyuan/kernel < 0.0.0-20260725123945-77421530be4a"],"patched":["github.com/siyuan-note/siyuan/kernel 0.0.0-20260725123945-77421530be4a"],"published":"2026-09-04","updated":"2026-09-10","sourceUpdated":"2026-09-10T15:25:33.033284583Z","source":"OSV","sourceUrl":"https://osv.dev/vulnerability/GHSA-34fj-mwm6-fjfg","references":[{"url":"https://github.com/siyuan-note/siyuan/security/advisories/GHSA-34fj-mwm6-fjfg"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-72794"},{"url":"https://github.com/siyuan-note/siyuan/commit/77421530be4ab1f43310d0f50fbab05d16c38675"},{"url":"https://github.com/siyuan-note/siyuan"},{"url":"https://www.vulncheck.com/advisories/siyuan-before-session-cookie-key-disclosure-via-getconf"},{"url":"https://github.com/advisories/GHSA-34fj-mwm6-fjfg"}],"tags":["osv","go","ghsa"],"epss":0.00249,"epssPercentile":0.16556,"cwe":["CWE-522"],"ingestedAt":"2026-09-04T21:27:58.198Z","slug":"CVE-2026-72794","body":"## Overview\n\n**CVE:** This vulnerability corresponds to [CVE-2026-72794](https://nvd.nist.gov/vuln/detail/CVE-2026-72794).\n\n### Summary\n\n`/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`.\n\nThe 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.\n\n### Details\n\n| Item | Detail |\n|---|---|\n| Route | `kernel/api/router.go:70` `POST /api/system/getConf` → `model.CheckAuth` → `getConf` |\n| Middleware | `CheckAuth` only — no `CheckReadonly`, no `CheckAdminRole` |\n| Leaked field | `AppConf.CookieKey`, serialized as `cookieKey` |\n| Purpose of the field | Signing key for the `siyuan` session cookie |\n\n**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:\n\n- `GetMaskedConf` masks `UserData`, `MCPOAuth` and `AccessAuthCode` only.\n- `HideConfSecret` nulls `AI`, `Api`, `Flashcard`, `ServerAddrs`, `Publish`, `Repo`, `Sync`, `Secrets`, `Variables` and the System paths. It contains no reference to `CookieKey`.\n- `FilterConfByPublishIgnore` touches `UILayout` only.\n- The browser-side strip removes System paths only.\n\n**The key is live, not vestigial.** It is passed straight into the session store at startup:\n\n```\ncli/cmd/serve.go:67   go server.Serve(false, model.Conf.CookieKey)\nkernel/server/serve.go:152   sessionStore = cookie.NewStore([]byte(cookieKey))\nkernel/server/serve.go:159   ginServer.Use(sessions.Sessions(\"siyuan\", sessionStore))\n```\n\n`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.\n\n**Guarded sibling, in the same file.** `exportConf` (`kernel/api/system.go:299`) clones the configuration before returning it and explicitly clears both secrets:\n\n```\nkernel/api/system.go:360   clonedConf.CookieKey = \"\"\n                           clonedConf.NotebookCrypto = nil\n```\n\nThe project has already classified `CookieKey` as a value that must not leave the server. The `getConf` masking path omits the same field.\n\n**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.\n\n### Proof of Concept\n\nPrecondition: publish mode enabled (default port 6808); anonymous when `Publish.Auth.Enable` is `false`, otherwise any publish reader account.\n\n```\nPOST http://127.0.0.1:6808/api/system/getConf\n{}\n\n→ 200\n   The response body's conf object contains a cookieKey field holding the\n   server's session-signing key in cleartext.\n```\n\nDifferential check against the endpoint that does strip it:\n\n```\nPOST http://127.0.0.1:6808/api/system/exportConf\n→ cookieKey is empty, notebookCrypto is null\n```\n\nThe same value is withheld by one endpoint and returned by the other.\n\n### Impact\n\nAn 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.\n\n### Suggested fix\n\nClear `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.\n\n## Affected packages\n\n- `github.com/siyuan-note/siyuan/kernel < 0.0.0-20260725123945-77421530be4a`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `github.com/siyuan-note/siyuan/kernel 0.0.0-20260725123945-77421530be4a`","depth":"twilight","depthScore":47,"depthScoreParts":{"impact":47.3,"likelihood":0,"exploitation":0,"ransomware":0},"changes":[]}