{"id":"CVE-2026-72810","aliases":["GHSA-mw8r-mw84-88v2"],"title":"SiYuan: Publish-boundary bypass via WebSocket broadcast: anonymous readers receive a live unfiltered feed of all edits including protected/forbidden documents (publish mode)","summary":"SiYuan: Publish-boundary bypass via WebSocket broadcast: anonymous readers receive a live unfiltered feed of all edits including protected/forbidden documents (publish mode)","severity":"high","cvss":8.6,"cwe":["CWE-862"],"vendor":"siyuan-note","product":"github.com/siyuan-note/siyuan/kernel","ecosystem":"go","affected":["github.com/siyuan-note/siyuan/kernel < 0.0.0-20260723013612-ba948639d7f6"],"patched":["github.com/siyuan-note/siyuan/kernel 0.0.0-20260723013612-ba948639d7f6"],"published":"2026-09-03","updated":"2026-09-03","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-mw8r-mw84-88v2","references":[{"url":"https://github.com/siyuan-note/siyuan/security/advisories/GHSA-mw8r-mw84-88v2"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-72810"},{"url":"https://github.com/siyuan-note/siyuan/commit/ba948639d7f6bd5594ce584072dc68310da87a68"},{"url":"https://www.vulncheck.com/advisories/siyuan-before-publish-boundary-bypass-via-websocket"},{"url":"https://github.com/advisories/GHSA-mw8r-mw84-88v2"}],"tags":["ghsa","go"],"epss":0.00538,"epssPercentile":0.42876,"ingestedAt":"2026-09-03T23:10:02.594Z","slug":"CVE-2026-72810","body":"## Overview\n\n**CVE:** This vulnerability corresponds to [CVE-2026-72810](https://nvd.nist.gov/vuln/detail/CVE-2026-72810).\n\n### Summary\n\nWebSocket sessions established through the publish surface (port 6808, `RoleReader` anonymous when `Publish.Auth.Enable` is `false`) are added to the same broadcast session pool as authenticated sessions. The kernel's broadcast functions push content events transactions carrying block DOM, document save/create, move/rename to every session in the pool with no role or publish-access filtering. As a result, an anonymous reader who holds a WebSocket connection open passively receives a real-time feed of every edit made in the workspace, including edits to password-protected, publish-forbidden, and unpublished documents. Because these events are delivered over the push channel and never pass through an HTTP handler, none of the publish-access filters that gate the HTTP endpoints apply.\n\n### Details\n\n**Session admission.** `HandleConnect` admits the injected `RoleReader` publish token, and the session is registered via `AddPushChan` into the same `sessions` pool used for authenticated clients.\n\n**Unfiltered broadcast.** The broadcast functions (`Broadcast`, `broadcastOthers`, `broadcastOtherAppMains`, …) write to every session in the pool with no role or publish-access check. The `isPublish` flag on a session is consulted only to send the \"service closed\" notice it is never used to gate content. Content events are pushed via `PushModeBroadcast → Broadcast()`, so transactions (with rendered block DOM), `savedoc`/create, and `moveDoc`/rename events reach the publish reader's socket unfiltered.\n\n**No HTTP filter applies.** This is a push channel, the events originate from the kernel's own edit pipeline and are broadcast directly to open sockets. They never traverse an HTTP handler, so the publish-access filters that gate the HTTP content endpoints (and the incomplete/missing filters reported separately on those endpoints) are not in the path at all. The WebSocket route (`/ws`) is `CheckAuth`-only, which the publish `RoleReader` token satisfies.\n\n### Proof of Concept\n\nReproduced on a local instance (SiYuan running locally, publish mode enabled on port 6808, publish Basic Auth disabled). An anonymous client (no token, no password) opens `wss://127.0.0.1:6808/ws` and holds it open while an administrator edits documents in the workspace.\n\nThe anonymous socket received, in real time and unfiltered:\n- `updateAttrs` with `name=WS_LEAK_SECRET_9931` on a block whose `rootID` is a **password-protected** document.\n- The secret title `WS_SECRET_DOC_7742` of a newly created document.\n- The create event carrying the notebook (box) name `CritChain` and the document path.\n\nNo HTTP request was made beyond the WebSocket upgrade; the content arrived over the push channel.\n\n### Impact\n\nAn anonymous reader (publish mode with auth disabled) or any publish `RoleReader` who merely holds a WebSocket connection open receives a live feed of every edit an administrator makes: block DOM, attributes, titles, notebook names, and document structure, including for password-protected, publish-forbidden, and unpublished documents. This defeats the publish-access and publish-password boundaries entirely for any content edited while the socket is open. The precondition is trivial: an administrator active in the workspace while the anonymous socket is connected. Confidentiality-only (passive disclosure); the channel is receive-only for the reader. Encrypted-notebook content follows the same broadcast path if edited while unlocked.\n\n### Suggested fix\n\nFilter broadcasts by session before writing: for any session flagged `isPublish`, apply the same publish-access/publish-ignore/publish-password checks used on the HTTP content path before pushing a content event, or exclude publish sessions from content broadcasts entirely and deliver only the events a publish viewer is authorized to see. The `isPublish` flag is already present on the session; it should gate content, not only the service-closed notice.\n\n## Affected packages\n\n- `github.com/siyuan-note/siyuan/kernel < 0.0.0-20260723013612-ba948639d7f6`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `github.com/siyuan-note/siyuan/kernel 0.0.0-20260723013612-ba948639d7f6`","depth":"twilight","depthScore":47,"depthScoreParts":{"impact":47.3,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}