---
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.00422
epssPercentile: 0.33927
cwe:
  - CWE-522
ingestedAt: '2026-09-04T21:27:58.198Z'
---

## Overview

**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.

## Affected packages

- `github.com/siyuan-note/siyuan/kernel < 0.0.0-20260725123945-77421530be4a`

## Remediation

Upgrade to a patched release:

- `github.com/siyuan-note/siyuan/kernel 0.0.0-20260725123945-77421530be4a`
