GitHub Advisoryadvisory · Go

GHSA-7hm9-v7vf-7g4w SiYuan: Path Traversal via unvalidated avID in RenderAttributeView/AV read endpoints : reader-reachable cross-scope attribute-view disclosure

HIGH Published 2026-09-03 Modified 2026-09-03 Official page ↗
Aliases
CVE-2026-69086
Ecosystem
Go
Packages
github.com/siyuan-note/siyuan/kernel
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Weaknesses
CWE-22
Reviewed
2026-09-03

Affected packages

• Go github.com/siyuan-note/siyuan/kernel: < 0.0.0-20260720151813-0f5a0e7c67b0 → fixed in 0.0.0-20260720151813-0f5a0e7c67b0

Description

CVE: This vulnerability corresponds to CVE-2026-69086. Summary Four attribute-view read endpoints build a filesystem path from a caller-controlled `id`/`avID` and read it without confining the result to the attribute-view storage directory (`DataDir/storage/av/`). On the load (file-exists) code path there is no boundary check, so an `avID` containing `../` segments escapes `storage/av/` and causes the kernel to read a `.json` file elsewhere in the workspace. The endpoints require only `CheckAuth`, which the publish service's `RoleReader` token satisfies; when `Publish.Auth.Enable` is `false` the publish proxy uses the anonymous account, making the surface reachable with no credentials. Details Affected endpoints (all gated by `CheckAuth` only, no `CheckAdminRole`): • `POST /api/av/renderAttributeView` &nbsp;→ `arg["id"]` • `POST /api/av/getAttributeViewKeysByID` → `arg["avID"]` • `POST /api/av/getAttributeViewKeys` &nbsp;→ `arg["id"]` • `POST /api/av/getCurrentAttrViewImages` → `arg["id"]` In `model.RenderAttributeView` (`model/attribute_view_render.go`), the only identifier guard `ast.IsNodeIDPattern(avID)` sits inside the `if !filelock.IsExist(existPath)` (create) branch: ```go existPath = GetAttributeViewDataPath(avID) // path built from avID, no check if !filelock.IsExist(existPath) { // NOT-EXIST / CREATE branch if !createIfNotExist { return // NotFound } if !ast.IsNodeIDPattern(avID) { // attributeViewDataPathByBox / GetAttributeViewDataPath avJSONPath = filepath.Join(DataDir, "storage", "av", avID+".json") // no boundary check // -> parseAttributeViewByPathInBox(avJSONPath, boxID) data, _ = filelock.ReadFile(avJSONPath) // SINK ``` `filepath.Join` cleans the path but does not reject `..` segments, so it provides no containment. The three `getAttributeView*` endpoints call `ParseAttributeView` with no create branch at all, so they never even reach the `ast.IsNodeIDPattern` check same defect, same auth tier. The root cause is that identifier validation is placed on a single code branch rather than confining the load to the AV base directory, so the load path reads a caller-controlled location. PoC Precondition: publish mode enabled (default port `6808`); reachable by a `RoleReader` publish token, or anonymously when `Publish.Auth.Enable` is `false`. A request to `/api/av/renderAttributeView` with an `id` composed of `../` path segments that resolves to an existing `.json` file outside `DataDir/storage/av/` causes that file to be read and parsed instead of being rejected, because the identifier validation is only reached on the not-exist/create branch. I have withheld the exact encoded `id` value from this draft to avoid publishing a live traversal against internet-exposed publish instances. I'm happy to provide the precise value and a screenshot privately in this thread on request. Impact An authenticated publish `RoleReader` or an anonymous client when publish auth is disabled can cause the kernel to read `.json` files outside the attribute-view directory. Because the loaded file is unmarshalled into the attribute-view structure, the reliable primitives are: 1. Disclosure of attribute-view (database) content from other scopes/notebooks the reader is not authorized to see. 2. A `.json`-path existence oracle for arbitrary workspace locations. Files not conforming to the AV schema are read but reflect little content, and the `.json` suffix is force-appended, so this is not a general arbitrary-file read. No admin role, CSRF token, or write permission is required. Suggested fix Validate `avID` with `ast.IsNodeIDPattern` before path construction on all branches (move it ahead of `FindAttributeViewPath` / `GetAttributeViewDataPath`), or preferably, so every caller inherits it confine at the sink: in `attributeViewDataPathByBox` / `GetAttributeViewDataPath`, compute the joined path and reject it unless `filepath.Rel(avBaseDir, cleaned)` stays within `avBaseDir` (no leading `..`). Sink-side confinement also covers the three `getAttributeView*` endpoints that never reach the create-branch guard.

Related

Alias · CVE (1)

  • CVE-2026-69086 SiYuan versions before v3.7.3 fail to validate the avID parameter on all code branches in attribute-view read endpoints, allowing attackers… vulnerability

Weakness · CWE (1)

  • CWE-22 Improper Limitation of a Pathname to a Restricted Directory weakness

References