# SiYuan: Non-administrator responses from /api/system/getConf omit three secrets that the configuration-export path explicitly strips, disclosing the session-cookie signing key and the OS username to anonymous readers

SiYuan's /api/system/getConf blocklist omits cookieKey, export.pandocBin and notebookCrypto, leaking the session-signing key and OS username to anonymous publish readers.

- Payout: Research
- Severity: high
- Program: SiYuan
- Found by (vendor credit): Shirshakhtml
- Found by: Shirshakhtml
- Disclosed: 2026-09-04
- CVE: CVE-2026-72793
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-h4v5-crx2-3cv4
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-h4v5-crx2-3cv4
- Tags: area:web domain:oss domain:web impact:ato impact:data-leak kind:research platform:ghsa sev:high tech:go technique:source-review vuln:auth-bypass vuln:info-disclosure vuln:secrets-leak

**Target:** POST /api/system/getConf kernel API endpoint
**Root cause:** getConf's non-administrator masking is a field-by-field blocklist (HideConfSecret plus a browser-request System.* strip) that diverged from exportConf's own secret-clearing inventory, so CookieKey, Export.PandocBin and NotebookCrypto are never cleared on the reader path.
**Steps:**
1. Enable publish mode (default port 6808); anonymous if `Publish.Auth.Enable` is false, else use any publish RoleReader account.
2. Send `POST http://127.0.0.1:6808/api/system/getConf` with body `{}`.
3. Observe 200 response containing `cookieKey`, `export.pandocBin` (e.g. `C:\Users\<username>\SiYuan\temp\pandoc\bin\pandoc.exe`) and `notebookCrypto`.
4. Differential check: `POST /api/system/exportConf` on the same instance returns `cookieKey` empty, `export.pandocBin` empty, `notebookCrypto` null.
**How found:** Compared the two endpoints in the same file: exportConf clones config and explicitly clears CookieKey, NotebookCrypto, Export.PandocBin, Account, Stat, System.ID and AI keys, while getConf's reader path uses a separate shorter blocklist. Noticed the browser-request strip at system.go:630 blanks only System.* paths with a comment about avoiding username leakage, yet Export.PandocBin carries the same username through the same response.
**Exploitation:** Attacker reads cookieKey, which is passed to `cookie.NewStore([]byte(cookieKey))` and used as the gorilla/securecookie HMAC key for the `siyuan` session cookie, allowing forged/tampered session cookies the server accepts. Escalation to admin additionally needs the forged SessionData to carry the matching AccessAuthCode (masked) or the instance to have no access-auth code configured, a common deployment.
**Escalation:** Forge a session cookie signed with the leaked cookieKey; on instances without an access-auth code, craft SessionData granting administrator.
**Insight:** When a codebase has two inventories of secrets (an export/serialization cloner and a response masker), diff them field by field — the masker is a blocklist and will lag. Also check privacy strips that enumerate one struct namespace (System.*) for sibling fields in other structs carrying the same data (Export.PandocBin).

## Proof of concept (copied exactly from the original report)

**POST getConf request returning secrets**

```
POST http://127.0.0.1:6808/api/system/getConf
{}

→ 200. The conf object contains:
     cookieKey          — the session-signing key, cleartext
     export.pandocBin   — absolute path containing the OS username
     notebookCrypto     — encrypted-notebook key material
```

**Differential exportConf check**

```
POST http://127.0.0.1:6808/api/system/exportConf

→ cookieKey is empty, export.pandocBin is empty, notebookCrypto is null
```

