GHSA-mw8r-mw84-88v2
SiYuan: Publish-boundary bypass via WebSocket broadcast: anonymous readers receive a live unfiltered feed of all edits including protected/forbidden documents (publish mode)
Quick fix
GHSA-mw8r-mw84-88v2 — github.com/siyuan-note/siyuan/kernel: upgrade to the fixed version with the command below.
go get github.com/siyuan-note/siyuan/kernel@v0.0.0-20260723013612-ba948639d7f6Details
**CVE:** This vulnerability corresponds to [CVE-2026-72810](https://nvd.nist.gov/vuln/detail/CVE-2026-72810).
### Summary
WebSocket 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.
### Details
**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.
**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.
**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.
### Proof of Concept
Reproduced 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.
The anonymous socket received, in real time and unfiltered: - `updateAttrs` with `name=WS_LEAK_SECRET_9931` on a block whose `rootID` is a **password-protected** document. - The secret title `WS_SECRET_DOC_7742` of a newly created document. - The create event carrying the notebook (box) name `CritChain` and the document path.
No HTTP request was made beyond the WebSocket upgrade; the content arrived over the push channel.
### Impact
An 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.
### Suggested fix
Filter 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.
Are you affected?
Enter the version of the package you're using.
Affected packages
0Fixed in: 0.0.0-20260723013612-ba948639d7f6go get github.com/siyuan-note/siyuan/kernel@v0.0.0-20260723013612-ba948639d7f6References
- https://github.com/siyuan-note/siyuan/security/advisories/GHSA-mw8r-mw84-88v2[WEB]
- https://nvd.nist.gov/vuln/detail/CVE-2026-72810[ADVISORY]
- https://github.com/siyuan-note/siyuan/commit/ba948639d7f6bd5594ce584072dc68310da87a68[WEB]
- https://github.com/siyuan-note/siyuan[PACKAGE]
- https://www.vulncheck.com/advisories/siyuan-before-publish-boundary-bypass-via-websocket[WEB]