{"id":"CVE-2026-72803","aliases":["GHSA-qvq9-hq6p-v378"],"title":"SiYuan: Missing publish-access filter on getBlockAttrs and batchGetBlockAttrs discloses block attributes (name, alias, memo, custom fields) of protected documents","summary":"SiYuan: Missing publish-access filter on getBlockAttrs and batchGetBlockAttrs discloses block attributes (name, alias, memo, custom fields) of protected documents","severity":"medium","cvss":5.8,"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-20260724093256-229fdffd7e4a"],"patched":["github.com/siyuan-note/siyuan/kernel 0.0.0-20260724093256-229fdffd7e4a"],"published":"2026-09-03","updated":"2026-09-03","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-qvq9-hq6p-v378","references":[{"url":"https://github.com/siyuan-note/siyuan/security/advisories/GHSA-qvq9-hq6p-v378"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-72803"},{"url":"https://github.com/siyuan-note/siyuan/commit/229fdffd7e4afdef543d4d8495657fda8a369400"},{"url":"https://www.vulncheck.com/advisories/siyuan-before-information-disclosure-via-getblockattrs"},{"url":"https://github.com/advisories/GHSA-qvq9-hq6p-v378"}],"tags":["ghsa","go"],"epss":0.00237,"epssPercentile":0.14943,"ingestedAt":"2026-09-03T23:10:02.211Z","slug":"CVE-2026-72803","body":"## Overview\n\n**CVE:** This vulnerability corresponds to [CVE-2026-72803](https://nvd.nist.gov/vuln/detail/CVE-2026-72803).\n\n### Summary\n\n`POST /api/attr/getBlockAttrs` and `POST /api/attr/batchGetBlockAttrs` return a block's full attribute set (IAL) with no publish-access check. Both 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 the block's name, alias, memo, bookmark, tags, and every `custom-*` attribute including for blocks in publish-forbidden and password-protected documents. The batch variant accepts an ID list, making it a bulk extraction primitive.\n\n### Details\n\nNeither handler applies a filter:\n\n```go\n// /api/attr/getBlockAttrs      (router line 301)\nret.Data = sql.GetBlockAttrs(id)\n\n// /api/attr/batchGetBlockAttrs (router line 302)\nret.Data = sql.BatchGetBlockAttrs(idList)\n```\n\n`sql.GetBlockAttrs` is a direct database read returning the block's entire IAL: `name`, `alias`, `memo`, `bookmark`, `tags`, and any `custom-*` key/value the user has set. Several of these are user-authored free text memos in particular are freeform notes attached to a block so this is document content, not merely structural metadata.\n\n`batchGetBlockAttrs` takes an arbitrary list of block IDs in a single request, so an attacker holding a set of block IDs can sweep attributes across the entire workspace in one call.\n\n**Guarded-sibling asymmetry.** The sibling metadata endpoint `getBlockInfo` calls `checkBlockPublishAccess(c, id, ret)` before returning; `getBlockAttrs` and `batchGetBlockAttrs` call nothing.\n\nVerified at `origin/master`: both handler bodies contain no publish-access, publish-ignore, or readonly-role check, and both routes are registered `CheckAuth` without `CheckAdminRole`.\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. A document is marked publish-forbidden (or password-protected) and contains a block with a memo and a custom attribute set.\n\n**Single-block disclosure:**\n```\nPOST http://127.0.0.1:6808/api/attr/getBlockAttrs\n{\"id\":\"<BLOCK_ID_IN_PROTECTED_DOC>\"}\n```\nReturns the block's IAL: `name`, `alias`, `memo`, `bookmark`, `tags`, and all `custom-*` values.\n\n**Bulk disclosure:**\n```\nPOST http://127.0.0.1:6808/api/attr/batchGetBlockAttrs\n{\"ids\":[\"<ID1>\",\"<ID2>\",\"<ID3>\"]}\n```\nReturns the attribute sets for every supplied ID in one response, with no per-ID authorization.\n\n**Control:** the sibling `getBlockInfo` with the same block ID is refused by `checkBlockPublishAccess`, confirming the boundary is enforced elsewhere and omitted here.\n\n### Impact\n\nAn anonymous reader (publish mode with auth disabled) or any publish `RoleReader` can read block attributes belonging to publish-forbidden and password-protected documents, including user-authored memos and arbitrary `custom-*` values. The batch endpoint turns this into a bulk primitive: given a set of block IDs, an attacker retrieves attributes across the whole workspace in a single request. Confidentiality-only.\n\n### Suggested fix\n\nCall `checkBlockPublishAccess` in `getBlockAttrs` before returning, matching `getBlockInfo`. For `batchGetBlockAttrs`, apply the check per ID and drop unauthorized entries from the response rather than failing the whole batch.\n\n## Affected packages\n\n- `github.com/siyuan-note/siyuan/kernel < 0.0.0-20260724093256-229fdffd7e4a`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `github.com/siyuan-note/siyuan/kernel 0.0.0-20260724093256-229fdffd7e4a`","depth":"sunlit","depthScore":32,"depthScoreParts":{"impact":31.9,"likelihood":0,"exploitation":0,"ransomware":0},"changes":[]}