
An administrator marks a document as publish-disabled in SiYuan, expecting that setting to hold. CVE-2026-68587 shows it doesn’t always. Three endpoints built to compute editing transactions can be used instead to read the full rendered content of a document that was never supposed to be public, without authentication and without triggering the write action their names describe.
CVE-2026-68587 was identified and reported by Shirshak Roy, Security Engineer at Secnora, part of a broader set of eight SiYuan vulnerabilities he’s found across the platform. It’s the same pattern seen elsewhere in that set, a publish boundary that one code path enforces and a neighbouring code path forgets, and it’s worth understanding on its own terms because the mechanism differs from the others.
What SiYuan Is and Why Publish Mode Matters
SiYuan is an open-source, block-based note-taking and knowledge-management tool, similar in spirit to Notion or Obsidian, with a self-hosted publish mode that lets users expose selected documents to the web while keeping others private. Publish mode runs the kernel API on a separate port, fronted by a reader-role token. Documents get an explicit visible/disable flag set through “/api/filetree/setPublishAccess” and the reader-facing content endpoint, “/api/filetree/getDoc” checks that flag before returning anything. That check is the publish boundary the product is built around, an administrator flips a document to publish-disabled and every reader-facing path is meant to honour it.
CVE-2026-68587: Vulnerability Details
- CVE ID: CVE-2026-68587
- Affected product: SiYuan kernel (backend/server component)
- Affected versions: All versions up to and including v3.7.2
- Patched version: v3.7.3
- Vulnerability class: Missing Authorization (CWE-862)
- CVSS v4.0 Base Score: 9.2 (CRITICAL)
- Vector: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N
- Impact: Confidentiality-only. No integrity or availability impact and the endpoints perform no mutation on the disclosure path
- Scope: Documents an administrator has explicitly marked publish-disabled
At the root of it, the vulnerability comes down to an authorization gap – three endpoints that compute editing transactions return fully rendered document content without ever checking whether the requester is allowed to read that content in the first place.
How CVE-2026-68587 Works
CVE-2026-68587 exists because three endpoints, getHeadingDeleteTransaction, getHeadingLevelTransaction and getHeadingInsertTransaction, don’t honour it. All three are registered under CheckAuth only, with no CheckAdminRole gate. CheckAuth admits the publish RoleReader token and when Publish.Auth.Enable is set to false, it admits the anonymous account as well. So any reader who can reach the publish port can call these endpoints.
The naming is the trap. Each endpoint is built to compute a transaction, the operations a delete, a heading-level change or an insert would produce and hand that transaction back to the client. On this code path, nothing gets deleted, changed or inserted. The endpoint loads the target heading’s block tree, renders it to DOM through RenderNodeBlockDOM and embeds that rendered content inside the returned transaction object. It reads like a write-only utility and behaves like a content-read endpoint.
Compare that to how SiYuan protects reads elsewhere. The reader-facing getDoc path runs content through IsReadOnlyRoleContext, the publish-access filter, before returning it. The admin-gated getBlockDOM and getBlockKramdown endpoints sit behind CheckAdminRole. Neither the publish filter nor the admin gate is applied to the three transaction endpoints. They return the same class of rendered DOM as those protected paths, just through a route that nobody thought to check for it, which is exactly the failure mode of this advisory document.
Each of the three handlers takes the same input, a single heading block ID and produces the same disclosure. getHeadingDeleteTransaction walks the heading’s subtree to build the set of operations an undo would need and that set carries the rendered content along with it. getHeadingLevelTransaction does the equivalent for a heading-level change and getHeadingInsertTransaction for an insert. None of the three writes anything on this path; all three read and render before the write would even happen and the response goes back to the caller regardless of whether the caller has any right to see it.
Reproducing CVE-2026-68587
The advisory’s proof of concept is straightforward and doesn’t need much more than a way to send POST requests. An administrator first marks a test document as publish-disabled through setPublishAccess, with a heading inside it containing a unique marker string. A baseline call to getDoc on the publish port, made anonymously, correctly returns a blocked response, confirming the publish filter works as intended on that path.
The disclosure step is a single anonymous POST to getHeadingDeleteTransaction on the publish port, passing only the heading’s block ID. The response comes back HTTP 200 and the undoOperations data inside it contains the full rendered HTML of the heading subtree, marker string included. Nothing was deleted. The same request pattern against getHeadingLevelTransaction and getHeadingInsertTransaction returns identical results. Three endpoints, one missing check, one working exploit path.
What an Attacker Actually Needs
CVE-2026-68587 has one real precondition, the attacker needs the target heading’s block ID. Block IDs in SiYuan are high-entropy and the vulnerable endpoints don’t hand them out, so on its own this issue doesn’t let someone enumerate arbitrary publish-disabled documents blind. The advisory is direct about the chaining risk, though.
Heading and block IDs for publish-disabled documents are obtainable from other CheckAuth-only endpoints that carry the same missing publish-access filter, including getHeadingChildrenIDs, which the advisory notes was reported separately. Chain an ID-disclosure endpoint with CVE-2026-68587 and the result is end-to-end, unauthenticated content disclosure with no attacker-supplied knowledge required going in.
That chaining pattern is worth flagging beyond this one product. A single missing check rarely stands alone in a codebase; if one handler in a family skips a filter, sibling handlers built the same way are worth auditing on the same pass, not treated as isolated findings.
Why This Matters for Organisations Running SiYuan
Organisations running self-hosted SiYuan instances for internal documentation, knowledge bases or client-facing published notes carry direct exposure here. Publish mode is specifically the feature meant to let teams control what leaves the building. This flaw shows that a document marked publish-disabled by an administrator, whether it holds draft contracts, internal architecture notes or anything else deliberately withheld from readers, could still be pulled by anyone who reaches the publish port and supplies the right block ID.
Confidentiality is the whole impact here, no accounts are created, no data is altered and availability is untouched, but for a knowledge-management tool, read access to content the administrator explicitly restricted is the asset that matters most. For teams evaluating or running self-hosted note and documentation platforms more broadly, the same question is worth asking of any tool in the category, does every endpoint that can return rendered content actually check the access boundary or does that check only live on the endpoints a reviewer thought to test.
Publish and sharing features are usually reviewed as a single unit during procurement or security assessment, but as this advisory shows, the boundary can hold on the main content path and quietly fail on a handful of adjacent ones. A vulnerability assessment that walks the full API surface, not just the documented reader-facing routes, is the difference between catching this class of gap early and finding it the way this one was found.
This is also a useful case study in why authorization checks need to be verified per-endpoint, not assumed from an endpoint’s name or its position in the API surface. A function named for a mutation that happens to return read-sensitive data in its response payload is easy to miss in a security review that filters by HTTP verb intent rather than actual data flow. Teams building or auditing similar block-based, publish-capable applications should treat “does this endpoint return rendered content” as the question that matters, independent of what the endpoint is nominally for.
Remediation
SiYuan v3.7.3 addresses CVE-2026-68587 directly:
- Upgrade to SiYuan v3.7.3, which contains the fix. Versions up to and including v3.7.2 are affected.
- The advisory’s suggested fix is to apply the same IsReadOnlyRoleContext publish-access check used by getDoc to all three getHeading*Transaction handlers, or alternatively gate them behind CheckAdminRole, consistent with how getBlockDOM and getBlockKramdown are already handled.
- Organisations running self-hosted SiYuan instances, particularly with publish mode enabled, should prioritise the v3.7.3 upgrade and review publish-access settings on any document that was deliberately marked disabled.
- Encrypted notebooks are out of scope for this specific issue.
There is no interim mitigation available outside of patching. Security and IT teams managing self-hosted SiYuan deployments should treat this as a priority upgrade, particularly for instances with publish mode enabled in production.
Conclusion
CVE-2026-68587 is a well-scoped, confidentiality-only finding, three endpoints, one missing filter. Its value isn’t the blast radius, it’s the pattern. Endpoints named for writes can still leak reads, and a publish boundary is only as strong as its least-checked handler. CVE-2026-68584 ran through these exact three endpoints too, plus a couple of neighbours, but tripped a different gate, a missing password check rather than a missing publish-visibility check.
For teams running self-hosted knowledge-management platforms, that’s the actual lesson: audit every content-returning path against your access boundary, not just the ones with “get” in a read-sounding name. For a look at how a separate class of input-handling gap surfaced in the same product, see Secnora’s writeup on CVE-2026-69085‘s unauthenticated SQL injection in SiYuan’s searchDocs endpoint.
References