Threats Tagged 'ghsa-vg99-7gj7-2fr5'
1 threat
Most recently published first
| Severity | CVSS | Signals | Threat | Source | Published | Score and star |
|---|---|---|---|---|---|---|
| Medium | 6.9 | EPSS 0.3% | Medium6.9EPSS 0.3%CVE Database V5CVE-2026-73606 ### Summary `/api/block/getRefIDs` filters its results for reader roles through a helper that checks only the visibility tiers. The password tier is not checked, because the helper does not receive the request context and therefore cannot evaluate the publish auth cookie. A reader who has not entered a document's publish password learns that the document references a given block. A function ten lines away in the same file does perform the full check, on the same input type. ### Details **Route,** identical at `eef105683` (`kernel/api/router.go:235`) and dev `a7ae96ce` (`:245`): ```go ginServer.Handle("POST", "/api/block/getRefIDs", model.CheckAuth, getRefIDs) ``` No `CheckReadonly`, no `CheckAdminRole`. **The filter chain.** `getRefIDs` (`kernel/api/block.go:631`) checks `isEncryptedNotebookDeniedForPublish`, calls `model.GetBlockRefsInBox`, then for read-only roles: ```go publishIgnore := model.GetInvisiblePublishAccess(publishAccess) refDefs, originalRefBlockIDs = model.FilterRefDefsByPublishIgnore(publishIgnore, refDefs) ``` `FilterRefDefsByPublishIgnore` (`kernel/model/publish_access.go:1324`) collects the reference and definition identifiers, resolves their block trees, and delegates the decision to `FilterBlockTreesByPublishIgnore` (`:1314`), whose entire body is: ```go for id, bt := range bts { if CheckPathAccessableByPublishIgnore(bt.BoxID, bt.Path, publishIgnore) { ret[id] = bt } } ``` Inside that helper, `CheckPublishAuthCookie`, `GetPathPasswordByPublishAccess`, `checkBlockTreeAccessableByPublishAccess` and `password` all appear zero times. **The complete check exists in the same file.** `kernel/model/publish_access.go:431`: ```go func checkBlockTreeAccessableByPublishAccess(c *gin.Context, publishAccess PublishAccess, bt *treenode.BlockTree) bool { if bt == nil || IsEncryptedBoxDeniedByPublishAccess(bt.BoxID) { return false } publishIgnore := filterDisablePublishAccess(publishAccess) passwordID, password := GetPathPasswordByPublishAccess(bt.BoxID, bt.Path, publishAccess) return CheckPathAccessableByPublishIgnore(bt.BoxID, bt.Path, publishIgnore) && (password == "" || CheckPublishAuthCookie(c, passwordID, password)) } ``` Same package, same file, same `*treenode.BlockTree` input. One takes the context and evaluates the password; the other does not receive it and structurally cannot. **Route-level contrast.** The adjacent `getChildBlocks` and `getTailChildBlocks` both carry `model.CheckAdminRole`. **Note on a prior assessment.** `getRefIDs` has been described as correctly filtered because it calls a publish-access filter. It does. The filter it calls covers the visibility tiers only. ### Proof of Concept Kernel 3.7.2, publish mode on port 6808, `Publish.Auth.Enable` false, anonymous client. A public document referenced from a second document whose publish tier was changed between runs. `getRefIDs` was called anonymously each time. | Tier of the referring document | Anonymous result | |---|---| | Public | reference returned (baseline) | | Password-protected | **reference still returned** | | Hidden | `[]`, filtered | | Forbidden | `[]`, filtered | The hidden and forbidden rows confirm the filter runs and works. The password-protected row is the defect. ### Impact An anonymous reader in publish mode, or any publish `RoleReader`, learns that a password-protected document contains a reference to a given block, without entering that document's password, and receives the block identifiers involved. Scoped precisely: the response carries identifiers only. `type RefDefs { RefID string; DefIDs []string }`, returned alongside `originalRefBlockIDs`, a map of identifier to identifier. There is no reference text, title or content. The disclosure is the existence of a relationship, plus identifiers usable as input to other endpoints. Confidentiality only. ### Suggested fix Thread `*gin.Context` into `FilterRefDefsByPublishIgnore` and `FilterBlockTreesByPublishIgnore`, and use `checkBlockTreeAccessableByPublishAccess` in place of the bare `CheckPathAccessableByPublishIgnore` call, so the password tier and the encrypted-box check are both applied. | CVE Database V5 |
Showing 1–1 of 1 result