# SiYuan: Encrypted-notebook key-derivation material and wrapped notebook keys disclosed to anonymous readers, enabling offline master-password cracking

SiYuan's CheckAuth-only getConf and getNotebookConf endpoints leak Argon2id salt, KDF params, KEK verifier and wrapped DEK to anonymous readers, enabling offline master-password cracking.

- Payout: Research
- Severity: high
- Program: SiYuan
- Found by: Shirshakhtml
- Disclosed: 2026-09-03
- CVE: CVE-2026-72801
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-8x84-r2ff-h8pq
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-8x84-r2ff-h8pq
- Tags: area:web domain:api domain:web impact:data-leak kind:research platform:ghsa sev:high tech:go technique:source-review vuln:access-control vuln:crypto vuln:info-disclosure vuln:secrets-leak

**Target:** SiYuan kernel HTTP API (publish mode, port 6808)
**Root cause:** HideConfSecret() nulls a dozen secret config fields but omits NotebookCrypto, and getNotebookConf/getNotebookInfo apply no reader filtering, so BoxCrypt.WrappedDEK is returned to non-admin readers.
**Steps:**
1. Enable publish mode with an encrypted notebook; connect anonymously when Publish.Auth.Enable is false, else as a RoleReader.
2. `POST http://127.0.0.1:6808/api/system/getConf` with `{}` — response `notebookCrypto` contains `MasterSalt`, `KDFParams`, `KEKVerifier`, `VerifierNonce`, `KEKMAC` while other secrets are blanked.
3. `POST http://127.0.0.1:6808/api/notebook/getNotebookConf` with `{"notebook":"<NOTEBOOK_ID>"}` — response contains `BoxCrypt.WrappedDEK` and `WrapNonce`.
4. Offline: derive `KEK = Argon2id(guess, MasterSalt, KDFParams)`; accept guess if AES-GCM-decrypt(KEKVerifier, VerifierNonce) == magic or HMAC(KEK) == KEKMAC.
5. Unwrap WrappedDEK with recovered KEK to get the notebook DEK and decrypt every .sy file.
**How found:** Code review of the config-masking path: noticed HideConfSecret enumerates secret fields but has zero NotebookCrypto matches, FilterConfByPublishIgnore only touches UILayout, and the three routes are registered CheckAuth without CheckAdminRole — a guarded-sibling asymmetry versus lsNotebooks which does filter readers.
**Exploitation:** Anonymous or reader-level HTTP requests harvest salt, KDF cost params, verifier and wrapped DEK; cracking then runs entirely off-server with GPU parallelism, no rate limit or logging, and the recovered KEK unwraps the DEK for full notebook decryption.
**Escalation:** Single reader token yields material for every encrypted notebook on the instance, since MasterSalt/KEK are global and per-notebook WrappedDEKs are enumerable via getNotebookConf.
**Insight:** When a masking function enumerates secret fields by name, diff that list against the config struct's JSON-tagged fields — any non-`-` field omitted from the denylist leaks; also compare sibling endpoints (lsNotebooks filters, getNotebookConf doesn't) for missing reader filters.

