{"id":"CVE-2026-72800","aliases":["GHSA-5fhr-f75j-8wr9","GO-2026-6395"],"title":"SiYuan: Missing publish-access filter on getAttributeViewKeysByID discloses database column schema, plus two unscoped block-ID enumeratio…","summary":"SiYuan: Missing publish-access filter on getAttributeViewKeysByID discloses database column schema, plus two unscoped block-ID enumeration oracles (publish mode)","severity":"medium","cvss":5.8,"cvssVector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N","vendor":"siyuan-note","product":"github.com/siyuan-note/siyuan/kernel","ecosystem":"go","affected":["github.com/siyuan-note/siyuan/kernel < 0.0.0-20260724103335-f36331956ae9"],"patched":["github.com/siyuan-note/siyuan/kernel 0.0.0-20260724103335-f36331956ae9"],"published":"2026-09-03","updated":"2026-09-10","sourceUpdated":"2026-09-10T15:25:49.896754076Z","source":"OSV","sourceUrl":"https://osv.dev/vulnerability/GHSA-5fhr-f75j-8wr9","references":[{"url":"https://github.com/siyuan-note/siyuan/security/advisories/GHSA-5fhr-f75j-8wr9"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-72800"},{"url":"https://github.com/siyuan-note/siyuan/commit/931ba693375ea9877b2ef74f9bfb632fad5bab3f"},{"url":"https://github.com/siyuan-note/siyuan/commit/f36331956ae98fc5358f8f93bf1da3427221edf3"},{"url":"https://github.com/siyuan-note/siyuan"},{"url":"https://www.vulncheck.com/advisories/siyuan-before-information-disclosure-via-unfiltered-api"},{"url":"https://github.com/advisories/GHSA-5fhr-f75j-8wr9"}],"tags":["osv","go","ghsa"],"epss":0.00325,"epssPercentile":0.22911,"cwe":["CWE-862"],"ingestedAt":"2026-09-03T23:10:02.053Z","slug":"CVE-2026-72800","body":"## Overview\n\n**CVE:** This vulnerability corresponds to [CVE-2026-72800](https://nvd.nist.gov/vuln/detail/CVE-2026-72800).\n\n### Summary\n\n`POST /api/av/getAttributeViewKeysByID` returns a database's full column schema with no publish-access filtering, while its sibling `getAttributeViewKeys` applies the filter for reader sessions. Two further endpoints, `getBlockDefIDsByRefText` and `getBlockRelevantIDs` return workspace-wide block IDs with no publish scoping. All three are `CheckAuth`-only, so they are reachable by the publish `RoleReader` token and by the anonymous account when `Publish.Auth.Enable` is `false`.\n\n### Details\n\n**(a) `getAttributeViewKeysByID`: ungated column-schema disclosure**\n\nThe entire handler (`kernel/api/av.go`, router line 548):\n```go\nret.Data = model.GetAttributeViewKeysByID(avID, keyIDs...)   // no publish gate\n```\n\nWith an empty `keyIDs`, `GetAttributeViewKeysByID` calls `av.ParseAttributeView(avID)` and returns every column's `*av.Key`:\n\n| Field | Discloses |\n|---|---|\n| `Name`, `Desc` | column title and user-authored description |\n| `Options` | the full single/multi-select vocabulary and colours (e.g. status labels such as \"Fired\", \"Confidential\") |\n| `Template` | the column's Sprig template expression — logic and field references |\n| `Relation` | the target `avID`, allowing pivot to another database |\n| `Rollup`, `NumberFormat`, date config | further schema |\n\n**Guarded-sibling asymmetry, same file:** `getAttributeViewKeys` (router line 526) runs `FilterBlockAttributeViewKeysByPublishAccess(...)` when `IsReadOnlyRoleContext`. `getAttributeViewKeysByID` applies nothing. A reader who knows an `avID` — trivially harvested from the `data-av-id` attribute of any published document embedding a database obtains the schema of any database in the workspace, including those whose host documents are hidden, password-protected, or publish-forbidden. `Relation` targets allow walking to sibling databases.\n\n**(b) Two unscoped block-ID enumeration oracles**\n\nBoth `CheckAuth`-only with no publish gate. Neither returns content of its own, but both yield valid block IDs that other endpoints turn into content:\n\n- `getBlockDefIDsByRefText` (router line 237) → `GetBlockDefIDsByRefText(anchor)` returns the block IDs, workspace-wide and including private documents, whose reference/anchor text equals a caller-supplied string: a ref-text → ID oracle.\n- `getBlockRelevantIDs` (router line 274) → `GetBlockRelevantIDsInBox(id, <notebook from request>)` returns parent/previous/next block IDs and traverses decrypted encrypted-notebook structure while the notebook is unlocked, a tree-walk oracle.\n\nVerified at `origin/master` (`eef105683`): all three handler bodies contain no publish-access, publish-ignore, or readonly-role check; all three 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 database exists whose host document is publish-forbidden or password-protected.\n\n**(a) Column schema of any database:**\n```\nPOST http://127.0.0.1:6808/api/av/getAttributeViewKeysByID\n{\"avID\":\"<AV_ID>\"}\n```\nReturns every column's key object names, descriptions, select vocabularies, template expressions, and `Relation` target `avID`s for a database whose host document the reader may not access.\n\n**Control:** the sibling `getAttributeViewKeys` with the same `avID` returns filtered results for the same reader session, confirming the boundary is enforced there and omitted here.\n\n**(b) ID oracles:**\n```\nPOST http://127.0.0.1:6808/api/block/getBlockDefIDsByRefText\n{\"anchor\":\"<known ref text>\"}\n→ block IDs workspace-wide, including blocks in private documents\n\nPOST http://127.0.0.1:6808/api/block/getBlockRelevantIDs\n{\"id\":\"<BLOCK_ID>\",\"notebook\":\"<BOX_ID>\"}\n→ parent/previous/next block IDs; traverses encrypted-notebook structure when unlocked\n```\n\n### Impact\n\nAn anonymous reader (publish mode with auth disabled) or any publish `RoleReader` can read the complete column schema of any database in the workspace, including column descriptions, select-option vocabularies (which frequently encode sensitive category labels), template logic, and relation targets that permit pivoting to further databases regardless of whether the host document is hidden, password-protected, or excluded from publishing.\n\nThe two enumeration endpoints additionally supply valid block IDs across the publish boundary, including from encrypted notebooks while unlocked. This removes the \"attacker must already know a valid ID\" precondition from other block-read endpoints, converting ID knowledge into content disclosure. Confidentiality-only.\n\n### Note\n\ngetAttributeViewKeysByID is a distinct handler from getAttributeView; although column definitions also appear within the latter's response payload, a fix applied to one handler does not remediate the other, and getAttributeViewKeysByID has its own filtered sibling (getAttributeViewKeys) demonstrating the intended treatment.\n\n### Suggested fix\n\n- Gate `getAttributeViewKeysByID` with `FilterBlockAttributeViewKeysByPublishAccess`, mirroring `getAttributeViewKeys`.\n- Scope `getBlockDefIDsByRefText` and `getBlockRelevantIDs` to publish-accessible blocks for reader sessions, and ensure the `*InBox` traversal path applies the same check before walking encrypted-notebook structure.\n\n## Affected packages\n\n- `github.com/siyuan-note/siyuan/kernel < 0.0.0-20260724103335-f36331956ae9`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `github.com/siyuan-note/siyuan/kernel 0.0.0-20260724103335-f36331956ae9`","depth":"sunlit","depthScore":32,"depthScoreParts":{"impact":31.9,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}