Root Cause Analysis
The vulnerability is a path traversal issue in SiYuan, identified as CVE-2026-69086. The root cause is the improper validation of user-supplied identifiers (avID and id) in several API endpoints related to attribute views. The application constructs file paths using these identifiers without properly sanitizing them or restricting them to the intended directory. The core of the vulnerability lies in the fact that the validation logic, ast.IsNodeIDPattern(avID), was either missing entirely or was placed in a conditional code path that was not executed when a malicious path pointed to an existing file. This allowed an attacker to use ../ sequences to traverse the file system and read arbitrary .json files from outside the intended storage/av/ directory. The analysis of the patch commit 0f5a0e7c67b0c2c7e9477d8f23db0fa73809e5e3 confirms this. The fix involves adding or moving the ast.IsNodeIDPattern check to the beginning of the affected functions, ensuring that the identifier is always validated before being used in any file path operations. The identified vulnerable functions are the ones that were directly involved in handling the tainted identifiers and constructing file paths, as evidenced by the changes in the patch.
Vulnerable functions
av.ParseAttributeViewkernel/av/av.go
This function is called by the API endpoints `getAttributeViewKeysByID` and `getAttributeViewKeys`. In the vulnerable version, it lacked a check to validate the format of `avID`. An attacker could provide a crafted `avID` with path traversal characters (`../`) to access arbitrary `.json` files on the filesystem. The patch added a check `!ast.IsNodeIDPattern(avID)` to validate the ID before any file operations.
model.RenderAttributeViewWithTargetkernel/model/attribute_view_render.go
This function is called by the `/api/av/renderAttributeView` endpoint. The vulnerability existed because the validation of `avID` using `ast.IsNodeIDPattern(avID)` was performed only within a conditional block that was executed when a file did not exist. If an attacker provided a path to an existing file using path traversal, the validation was skipped, and the function would proceed to read and parse an arbitrary `.json` file. The patch moved the validation to the beginning of the function, ensuring it's always executed.
av.GetAttributeViewDataPathkernel/av/av.go
This function constructs the full path to an attribute view's data file. It was vulnerable because it did not validate the `avID` before joining it into a file path. This allowed for path traversal attacks. The patch added the `!ast.IsNodeIDPattern(avID)` check to prevent this.
av.attributeViewDataPathByBoxkernel/av/encrypted_hook.go
This function is another utility for constructing file paths for attribute views, specifically for different 'boxes' (notebooks). It was vulnerable to path traversal through both `avID` and `boxID` as it lacked validation. The patch added checks for both parameters using `ast.IsNodeIDPattern`.
model.RenderRepoSnapshotAttributeViewkernel/model/attribute_view_render.go
Similar to `RenderAttributeViewWithTarget`, this function also had conditional validation of `avID` that could be bypassed if the target file already existed. The patch moved the `ast.IsNodeIDPattern` check to the beginning of the function.
model.RenderHistoryAttributeViewkernel/model/attribute_view_render.go
Similar to `RenderAttributeViewWithTarget`, this function also had conditional validation of `avID` that could be bypassed if the target file already existed. The patch moved the `ast.IsNodeIDPattern` check to the beginning of the function.
av.ParseAttributeViewInBoxkernel/av/av.go
This function is used to parse attribute views within a specific box. It was vulnerable because it did not validate `avID` or `boxID` before using them to construct a file path. The patch added `ast.IsNodeIDPattern` checks for both `avID` and `boxID`.
av.SaveAttributeViewkernel/av/av.go
This function saves an attribute view. While not directly a read vulnerability, the lack of proper `av.ID` validation could lead to issues if an invalid ID was saved, potentially affecting path construction later. The patch changed a simple empty string check to a more robust `ast.IsNodeIDPattern` validation.
av.FindAttributeViewPathkernel/av/encrypted_hook.go
This function finds the path to an attribute view. It was vulnerable because it used `avID` to construct paths without prior validation, allowing path traversal. The patch added an `ast.IsNodeIDPattern` check for `avID`.
av.FindAttributeViewPathInBoxkernel/av/encrypted_hook.go
This function finds the path to an attribute view within a specific box. It was vulnerable because it used `avID` and `boxID` to construct paths without prior validation, allowing path traversal. The patch added `ast.IsNodeIDPattern` checks for both `avID` and `boxID`.
av.writeAttributeViewDatakernel/av/encrypted_hook.go
This function writes attribute view data to a file. Although the CVE focuses on read operations, this function was also vulnerable to path traversal if `avID` or `boxID` were malicious, potentially leading to arbitrary file writes. The patch added `ast.IsNodeIDPattern` checks for both `avID` and `boxID`.