CVE-2026-72805 is a medium-severity (CVSS 5.8) CWE-862 vulnerability in github.com/siyuan-note/siyuan/kernel. O3 Security confirms whether CVE-2026-72805 is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.
SiYuan: Missing publish-access check on getBlockBreadcrumb, getRefText, and getBlockTreeInfos discloses content and metadata of protected/forbidden documents
Real-World Exposure
github.com/siyuan-note/siyuan/kernelReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.
Description
CVE: This vulnerability corresponds to CVE-2026-72805.
Summary
Three block endpoints return document content snippets and metadata without any publish-access check, while their sibling getBlockInfo which returns comparable data does enforce one. All three are CheckAuth-only, so they are reachable by the publish RoleReader token and by the anonymous account when Publish.Auth.Enable is false. An anonymous reader supplying a block ID receives content and metadata belonging to publish-forbidden and password-protected documents.
Details
getBlockInfo (kernel/api/block.go) gates on the publish boundary:
if !checkBlockPublishAccess(c, id, ret) {
return
}
The following siblings in the same file perform no equivalent check:
| Endpoint | Returns | Publish check |
|---|---|---|
getBlockInfo | root/title/path metadata | checkBlockPublishAccess: present |
getBlockBreadcrumb | BlockPath.Name : root document title plus every ancestor block's content snippet | none |
getRefText | the block's reference/anchor text (document content) | none |
getBlockTreeInfos | root/title/path metadata for arbitrary block IDs | none |
getBlockBreadcrumb returns the full ancestor chain including each ancestor block's content snippet, and getRefText returns block anchor text both are document content, not just metadata. getBlockTreeInfos returns root/title/path for any caller-supplied ID set via model.GetBlockTreeInfosInBox(...) with no gate.
getBlockBreadcrumb and getRefText additionally accept a client-supplied notebook argument that routes to the *InBox variants, so the same unguarded path applies to encrypted-notebook reads while the notebook is unlocked.
The correct primitive already exists in the codebase and is used by getBlockInfo; these three handlers simply do not call it.
Proof of Concept
Precondition: publish mode enabled (default port 6808); anonymous when Publish.Auth.Enable is false, otherwise any publish reader account. A document D is marked publish-forbidden (or password-protected) and contains a block BLOCK_ID under a heading with distinctive content.
Control: the gated sibling correctly refuses:
POST http://127.0.0.1:6808/api/block/getBlockInfo
{"id":"BLOCK_ID"}
Blocked by checkBlockPublishAccess.
Disclosure: the ungated siblings return the data anyway:
POST http://127.0.0.1:6808/api/block/getBlockBreadcrumb
{"id":"BLOCK_ID"}
→ ancestor chain including the forbidden document's title and ancestor block content snippets
POST http://127.0.0.1:6808/api/block/getRefText
{"id":"BLOCK_ID"}
→ the block's reference/anchor text (content of the forbidden document)
POST http://127.0.0.1:6808/api/block/getBlockTreeInfos
{"ids":["BLOCK_ID"]}
→ root ID, title, and path for the forbidden document
Verified by code inspection at origin/master (eef10568): getBlockInfo contains the checkBlockPublishAccess call; getBlockBreadcrumb, getRefText, and getBlockTreeInfos contain no publish-access, publish-ignore, or readonly-role check in their bodies.
Impact
An anonymous reader (publish mode with auth disabled) or any publish RoleReader can read, for documents explicitly excluded from publishing or protected by a publish password:
- the document title and full ancestor chain, including ancestor block content snippets (
getBlockBreadcrumb); - block reference/anchor text, i.e. document content (
getRefText); - root ID, title, and path metadata for arbitrary block IDs (
getBlockTreeInfos).
Because getBlockBreadcrumb and getRefText accept a notebook argument routing to the *InBox variants, the same disclosure applies to encrypted notebooks while unlocked. Confidentiality-only; the precondition is a block ID, obtainable from other reader-reachable endpoints.
Suggested fix
Call checkBlockPublishAccess (as getBlockInfo does) in getBlockBreadcrumb, getRefText, and getBlockTreeInfos before returning data for getBlockTreeInfos, apply it per ID and drop unauthorized entries. Confirm the *InBox variants (GetBlockRefTextInBox, BuildBlockBreadcrumbInBox) enforce the same boundary so the notebook-argument path is covered.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐹Go | github.com/siyuan-note/siyuan/kernel | all versions | 0.0.0-20260723163028-931ba693375e |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/siyuan-note/siyuan/kernel. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.
Fix
Update github.com/siyuan-note/siyuan/kernel to 0.0.0-20260723163028-931ba693375e or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-72805 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 pinpoints whether CVE-2026-72805 is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.
Tailored to CVE-2026-72805. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is CVE-2026-72805 in your dependencies?
O3 detects CVE-2026-72805 across Go dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.