CVE-2026-72789: SiYuan The Publish-access Gate Treats Encrypted Vulnerability

HIGH
Advisory Identifier: GHSA-v684-q882-jgmq
CVSS 8.6
CWE-862
Published
Advisory Summary

CVE-2026-72789 is a HIGH (CVSS 8.6) the publish-access gate treats encrypted vulnerability (CWE-862: Missing Authorization) affecting SiYuan libraries in the Go ecosystem. The issue involves the publish-access gate treats encrypted notebooks as publicly accessible by default, allowing anonymous readers to retrieve fully decrypted document content while a notebook is unlocked. Remediation is available by upgrading affected packages to version 0.0.0-20260726020813-a25c2dd06aae.

CVE-2026-72789 at a Glance

CVE Identifier CVE-2026-72789
GHSA Identifier GHSA-v684-q882-jgmq
Severity HIGH
CVSS v3.1 Base Score 8.6
CWE Classification CWE-862: Missing Authorization
Affected Product SiYuan
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 8.6

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Changed (S:C)
Confidentiality High (C:H)
Integrity None (I:N)
Availability None (A:N)

How to Fix CVE-2026-72789

To remediate this vulnerability, upgrade all affected SiYuan dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/siyuan-note/siyuan/kernel fixed: 0.0.0-20260726020813-a25c2dd06aae
Upgrade github.com/siyuan-note/siyuan/kernel to 0.0.0-20260726020813-a25c2dd06aae
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/siyuan-note/siyuan/kernel

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-72789, inspect your project dependencies for SiYuan:

inspect dependencies for github.com/siyuan-note/siyuan/kernel

Analyze the terminal output to locate any version of SiYuan in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.0.0-20260726020813-a25c2dd06aae), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-862: Missing Authorization, where the product does not perform an authorization check when an actor attempts to access a resource or perform an action. In SiYuan, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

**CVE:** This vulnerability corresponds to [CVE-2026-72789](https://nvd.nist.gov/vuln/detail/CVE-2026-72789). ### Summary `publishAccess.json` is an opt-out list. The publish gate returns *accessible* for anything not explicitly listed in it. Encrypted notebooks are never written into that file, because only the administrator-gated `setPublishAccess` writes it and no part of the encryption subsystem does. Consequently every encrypted notebook is publish-accessible as far as the gate is concerned. While an encrypted notebook is unlocked, an anonymous reader in publish mode can list it, enumerate its documents, and retrieve their fully decrypted content. No key material, no password, and no cracking is involved. The kernel decrypts the data and serves it because the authorization layer never asks whether the notebook is encrypted. This is reported as a defect in the gate rather than in any individual handler. Endpoints that were previously reviewed and found to apply the correct checks do apply them. The checks return true. ### Details **The gate defaults to accessible.** `CheckPathAccessableByPublishIgnore(box, path, ignore)` iterates the ignore list and returns false only on a match: ```go for _, item := range publishIgnore { if item.ID == box || strings.Contains(path, item.ID) { return false } } return true // unlisted means accessible ``` **Encrypted notebooks are never listed.** `publishAccess.json` is written only by `setPublishAccess` (`kernel/api/router.go:169`), which carries `CheckAdminRole` and `CheckReadonly`. Nothing in `crypto.go`, `encrypted_ops.go` or `notebook_crypto.go` writes to it. An administrator would have to manually add each encrypted notebook to the ignore list to protect it, and nothing in the product prompts or documents that. **Neither core gate rejects them.** On both `eef105683` and `v3.7.4-alpha.1`: ```go func checkBlockTreeAccessableByPublishAccess(...) bool { return CheckPathAccessableByPublishIgnore(bt.BoxID, bt.Path, publishIgnore) && (password == "" || CheckPublishAuthCookie(c, passwordID, password)) } ``` For an encrypted notebook the first term is true because it is unlisted, and the second is true because encrypted notebooks carry no publish password. The conjunction returns true. `IsEncryptedBox` does not appear in `kernel/model/publish_access.go` at all on master. On the development branch it appears once, inside `parseAttributeViewForPublishAccess`, where it routes *into* encrypted boxes rather than excluding them. The publish authorization layer has no concept of an encrypted notebook. **The chain.** Verified on the development branch, which is the harder target because the block-metadata, attribute-view, path-resolution and encrypted-notebook-status fixes have all landed there. 1. `lsNotebooks` calls `ListNotebooks()`, which includes encrypted notebooks and reports `Encrypted: boxConf.Encrypted` without filtering on it. The reader filter skips only notebooks that are `Closed` or publish-invisible. An unlocked encrypted notebook is neither, so it is returned to an anonymous reader together with its identifier. 2. `listDocsByPath{notebook: <encrypted box id>, path: "/"}` applies only `CheckPathAccessableByPublishIgnore`, which passes, returning the document identifiers and titles inside the encrypted notebook. 3. `getDoc` routes to `GetDocInBox(...)`, after which `FilterContentByPublishAccess(...)` returns the content unmodified because the box is unlisted. The response is the fully decrypted document. `getBlockKramdown` reaches `GetBlockKramdownInBox` for the same result in Markdown. Handlers reach the decrypted store through `encryptedNotebookFromArg(arg)` on a client-supplied notebook argument. This function predates the current release and is not a recent addition. **The precondition is the unlock window.** `GetBlockTreeInBox` returns nil while a notebook is locked, treating it as nonexistent, and non-nil once unlocked. So the exposure is bounded to the period during which the legitimate user has the notebook open, which is precisely the period in which they are working in it. No action by the attacker triggers or extends that window, but no unusual condition is required either. **On endpoints previously assessed as correctly gated.** `getBlockDOM` and `getBlockKramdown` apply password and visibility checks. `exportPreview` applies `FilterContentByPublishAccess`. Those assessments are accurate and this report does not contradict them. The checks execute and return true, because the visibility term resolves to accessible for an unlisted box and the password term is vacuous for a notebook that has no publish password. Patching any individual handler would not change that result. ### Proof of Concept Precondition: publish mode enabled (default port 6808), anonymous when `Publish.Auth.Enable` is `false`, otherwise any publish reader account. An encrypted notebook that is currently unlocked by the legitimate user. Step 1, obtain the encrypted notebook's identifier: ``` POST http://127.0.0.1:6808/api/notebook/lsNotebooks {} → 200. The list includes the encrypted notebook, with encrypted: true and its id. ``` Step 2, enumerate its documents: ``` POST http://127.0.0.1:6808/api/filetree/listDocsByPath {"notebook":"<encrypted box id>","path":"/"} → 200, document identifiers and titles from inside the encrypted notebook ``` Step 3, retrieve decrypted content: ``` POST http://127.0.0.1:6808/api/filetree/getDoc {"id":"<document id from step 2>"} → 200, the fully decrypted document ``` `getBlockKramdown` returns the same content as decrypted Markdown. Repeating step 3 while the notebook is locked returns not-found, which confirms the unlock window is the only thing standing between an anonymous reader and the plaintext. ### Impact The confidentiality guarantee of the encrypted-notebook feature is defeated against a remote, unauthenticated attacker for as long as the notebook is unlocked. A user who encrypts a notebook is expressing that its contents should be protected beyond the ordinary publish boundary. The publish gate does not recognise that intent, and instead treats the notebook as publicly readable because nobody added it to an opt-out list that the encryption feature does not write to. The exposure is full document content rather than metadata, and it applies to every document in the notebook. It requires no key material, no password, no offline work and no interaction with the encryption subsystem at all. ### Suggested fix Fail closed on encryption, independently of `publishAccess.json`: ```go if IsEncryptedBox(bt.BoxID) { return false } ``` in both `checkBlockTreeAccessableByPublishAccess` and `CheckBlockTreeMetadataAccessableByPublishAccess`, and exclude encrypted notebooks from `lsNotebooks` and `listDocsByPath` for read-only roles. The broader point is the default. An opt-out authorization list means every future notebook type, storage backend or content class is publicly accessible until somebody remembers to add it. Encrypted notebooks are the case where that default is most clearly wrong, but they are unlikely to be the only one.

CVE-2026-72789 Affected SiYuan Versions

1 component(s)
Fixed Versions:
0.0.0-20260726020813-a25c2dd06aae
Product / Package Ecosystem Affected Versions Fixed Version
github.com/siyuan-note/siyuan/kernel
Go
< 0.0.0-20260726020813-a25c2dd06aae
0.0.0-20260726020813-a25c2dd06aae

References

Frequently Asked Questions

What is CVE-2026-72789?
CVE-2026-72789 is a security vulnerability in SiYuan involving The publish-access gate treats encrypted notebooks as publicly accessible by default, allowing anonymous readers to retrieve fully decrypted document content while a notebook is unlocked under CWE-862: Missing Authorization.
Which SiYuan versions are affected?
Affected versions include releases prior to 0.0.0-20260726020813-a25c2dd06aae across affected packages: github.com/siyuan-note/siyuan/kernel.
What version fixes CVE-2026-72789?
Upgrading to 0.0.0-20260726020813-a25c2dd06aae (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/siyuan-note/siyuan/kernel affected?
Yes, github.com/siyuan-note/siyuan/kernel is affected in releases prior to 0.0.0-20260726020813-a25c2dd06aae. Upgrade your dependency to 0.0.0-20260726020813-a25c2dd06aae or later.
What is the CVSS score of CVE-2026-72789?
CVE-2026-72789 has a CVSS v3.1 base score of 8.6 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N.
What CWE is associated with CVE-2026-72789?
CVE-2026-72789 is classified under CWE-862: Missing Authorization (The product does not perform an authorization check when an actor attempts to access a resource or perform an action.).
How can I check Go dependencies for CVE-2026-72789?
Run the dependency tree command: 'inspect dependencies for github.com/siyuan-note/siyuan/kernel'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-v684-q882-jgmq",
  "modified" : "2026-09-08T17:56:07Z",
  "published" : "2026-09-08T17:56:07Z",
  "aliases" : [ "CVE-2026-72789" ],
  "summary" : "SiYuan: The publish-access gate treats encrypted notebooks as publicly accessible by default, allowing anonymous readers to retrieve fully decrypted document content while a notebook is unlocked",
  "details" : "**CVE:** This vulnerability corresponds to [CVE-2026-72789](https://nvd.nist.gov/vuln/detail/CVE-2026-72789).\n\n### Summary\n\n`publishAccess.json` is an opt-out list. The publish gate returns *accessible* for anything not explicitly listed in it. Encrypted notebooks are never written into that file, because only the administrator-gated `setPublishAccess` writes it and no part of the encryption subsystem does. Consequently every encrypted notebook is publish-accessible as far as the gate is concerned.\n\nWhile an encrypted notebook is unlocked, an anonymous reader in publish mode can list it, enumerate its documents, and retrieve their fully decrypted content. No key material, no password, and no cracking is involved. The kernel decrypts the data and serves it because the authorization layer never asks whether the notebook is encrypted.\n\nThis is reported as a defect in the gate rather than in any individual handler. Endpoints that were previously reviewed and found to apply the correct checks do apply them. The checks return true.\n\n### Details\n\n**The gate defaults to accessible.** `CheckPathAccessableByPublishIgnore(box, path, ignore)` iterates the ignore list and returns false only on a match:\n\n```go\nfor _, item := range publishIgnore {\n    if item.ID == box || strings.Contains(path, item.ID) {\n        return false\n    }\n}\nreturn true   // unlisted means accessible\n```\n\n**Encrypted notebooks are never listed.** `publishAccess.json` is written only by `setPublishAccess` (`kernel/api/router.go:169`), which carries `CheckAdminRole` and `CheckReadonly`. Nothing in `crypto.go`, `encrypted_ops.go` or `notebook_crypto.go` writes to it. An administrator would have to manually add each encrypted notebook to the ignore list to protect it, and nothing in the product prompts or documents that.\n\n**Neither core gate rejects them.** On both `eef105683` and `v3.7.4-alpha.1`:\n\n```go\nfunc checkBlockTreeAccessableByPublishAccess(...) bool {\n    return CheckPathAccessableByPublishIgnore(bt.BoxID, bt.Path, publishIgnore) &&\n           (password == \"\" || CheckPublishAuthCookie(c, passwordID, password))\n}\n```\n\nFor an encrypted notebook the first term is true because it is unlisted, and the second is true because encrypted notebooks carry no publish password. The conjunction returns true.\n\n`IsEncryptedBox` does not appear in `kernel/model/publish_access.go` at all on master. On the development branch it appears once, inside `parseAttributeViewForPublishAccess`, where it routes *into* encrypted boxes rather than excluding them. The publish authorization layer has no concept of an encrypted notebook.\n\n**The chain.** Verified on the development branch, which is the harder target because the block-metadata, attribute-view, path-resolution and encrypted-notebook-status fixes have all landed there.\n\n1. `lsNotebooks` calls `ListNotebooks()`, which includes encrypted notebooks and reports `Encrypted: boxConf.Encrypted` without filtering on it. The reader filter skips only notebooks that are `Closed` or publish-invisible. An unlocked encrypted notebook is neither, so it is returned to an anonymous reader together with its identifier.\n2. `listDocsByPath{notebook: <encrypted box id>, path: \"/\"}` applies only `CheckPathAccessableByPublishIgnore`, which passes, returning the document identifiers and titles inside the encrypted notebook.\n3. `getDoc` routes to `GetDocInBox(...)`, after which `FilterContentByPublishAccess(...)` returns the content unmodified because the box is unlisted. The response is the fully decrypted document. `getBlockKramdown` reaches `GetBlockKramdownInBox` for the same result in Markdown.\n\nHandlers reach the decrypted store through `encryptedNotebookFromArg(arg)` on a client-supplied notebook argument. This function predates the current release and is not a recent addition.\n\n**The precondition is the unlock window.** `GetBlockTreeInBox` returns nil while a notebook is locked, treating it as nonexistent, and non-nil once unlocked. So the exposure is bounded to the period during which the legitimate user has the notebook open, which is precisely the period in which they are working in it. No action by the attacker triggers or extends that window, but no unusual condition is required either.\n\n**On endpoints previously assessed as correctly gated.** `getBlockDOM` and `getBlockKramdown` apply password and visibility checks. `exportPreview` applies `FilterContentByPublishAccess`. Those assessments are accurate and this report does not contradict them. The checks execute and return true, because the visibility term resolves to accessible for an unlisted box and the password term is vacuous for a notebook that has no publish password. Patching any individual handler would not change that result.\n\n### Proof of Concept\n\nPrecondition: publish mode enabled (default port 6808), anonymous when `Publish.Auth.Enable` is `false`, otherwise any publish reader account. An encrypted notebook that is currently unlocked by the legitimate user.\n\nStep 1, obtain the encrypted notebook's identifier:\n\n```\nPOST http://127.0.0.1:6808/api/notebook/lsNotebooks\n{}\n\n→ 200. The list includes the encrypted notebook, with encrypted: true and its id.\n```\n\nStep 2, enumerate its documents:\n\n```\nPOST http://127.0.0.1:6808/api/filetree/listDocsByPath\n{\"notebook\":\"<encrypted box id>\",\"path\":\"/\"}\n\n→ 200, document identifiers and titles from inside the encrypted notebook\n```\n\nStep 3, retrieve decrypted content:\n\n```\nPOST http://127.0.0.1:6808/api/filetree/getDoc\n{\"id\":\"<document id from step 2>\"}\n\n→ 200, the fully decrypted document\n```\n\n`getBlockKramdown` returns the same content as decrypted Markdown. Repeating step 3 while the notebook is locked returns not-found, which confirms the unlock window is the only thing standing between an anonymous reader and the plaintext.\n\n### Impact\n\nThe confidentiality guarantee of the encrypted-notebook feature is defeated against a remote, unauthenticated attacker for as long as the notebook is unlocked. A user who encrypts a notebook is expressing that its contents should be protected beyond the ordinary publish boundary. The publish gate does not recognise that intent, and instead treats the notebook as publicly readable because nobody added it to an opt-out list that the encryption feature does not write to.\n\nThe exposure is full document content rather than metadata, and it applies to every document in the notebook. It requires no key material, no password, no offline work and no interaction with the encryption subsystem at all.\n\n### Suggested fix\n\nFail closed on encryption, independently of `publishAccess.json`:\n\n```go\nif IsEncryptedBox(bt.BoxID) {\n    return false\n}\n```\n\nin both `checkBlockTreeAccessableByPublishAccess` and `CheckBlockTreeMetadataAccessableByPublishAccess`, and exclude encrypted notebooks from `lsNotebooks` and `listDocsByPath` for read-only roles.\n\nThe broader point is the default. An opt-out authorization list means every future notebook type, storage backend or content class is publicly accessible until somebody remembers to add it. Encrypted notebooks are the case where that default is most clearly wrong, but they are unlikely to be the only one.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/siyuan-note/siyuan/kernel"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.0.0-20260726020813-a25c2dd06aae"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/siyuan-note/siyuan/security/advisories/GHSA-v684-q882-jgmq"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-72789"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/siyuan-note/siyuan/commit/a25c2dd06aae13d1de70cc61cbf98169689c9d86"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/siyuan-note/siyuan"
  }, {
    "type" : "WEB",
    "url" : "https://www.vulncheck.com/advisories/siyuan-before-authentication-bypass-via-encrypted-notebooks"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-862" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-09-08T17:56:07Z",
    "nvd_published_at" : null
  }
}