CVE-2026-69086: SiYuan: path traversal leaks attribute-view data

GHSA-7hm9-v7vf-7g4wHIGHPoC AVAILABLE
Published September 3, 2026
CISO Take

SiYuan's attribute-view API endpoints build a filesystem path from a caller-supplied ID and, on the 'file exists' code path, skip identifier validation entirely, letting a `../`-laced avID escape the intended storage directory and force the kernel to read and parse an arbitrary existing `.json` file elsewhere in the workspace. This is reachable by any client holding a low-privilege RoleReader publish token, and when Publish.Auth.Enable is left at its default of false, by a fully anonymous client hitting the public-facing publish service on port 6808 — no admin role or CSRF token required. With 2,997 downstream dependents and 40 other CVEs already recorded against this package, the blast radius among SiYuan self-hosted knowledge bases is real, though the EPSS score of 0.35% (72nd percentile) and absence from CISA KEV or public exploit code suggest exploitation isn't yet trending. The primary risk is confidentiality only (CVSS 7.7, C:H/I:N/A:N): disclosure of attribute-view/database content from notebooks the reader shouldn't see, plus a file-existence oracle for arbitrary `.json` paths. Patch to kernel build 0.0.0-20260720151813-0f5a0e7c67b0 or later, and until then set Publish.Auth.Enable to true and rotate or restrict any RoleReader publish tokens to trusted parties.

Sources:NVDGitHub AdvisoryEPSSOpenSSFATLASvulncheck.com

What is the risk?

Exploitability is moderate: the flaw requires no admin privileges and can be triggered with a simple crafted HTTP request, but it does require the publish service to be exposed (default port 6808) and either a valid RoleReader token or Publish.Auth.Enable=false. No public PoC or Nuclei template exists yet, and EPSS sits at a low 0.35%, so opportunistic mass-exploitation is unlikely in the near term — this reads more as a targeted-disclosure risk than a worm-able bug. Impact is confined to confidentiality (CVSS 3.1: 7.7, S:C/C:H/I:N/A:N): no code execution, no data tampering, no denial of service, and the forced `.json` suffix limits it to structured attribute-view files rather than arbitrary file contents. Exposure is elevated for any internet-facing SiYuan publish instance, particularly self-hosted deployments where operators leave Publish.Auth.Enable at its insecure default.

How does the attack unfold?

Initial Access
Attacker locates an internet-exposed SiYuan publish instance (default port 6808) and either uses a low-privilege RoleReader token or connects anonymously when Publish.Auth.Enable is false.
AML.T0049
Exploitation
Attacker sends a request to /api/av/renderAttributeView (or a sibling endpoint) with an avID containing ../ segments that resolves to an existing .json file, bypassing the identifier check that only runs on the create branch.
Impact
The kernel reads and parses the out-of-scope .json file, disclosing attribute-view/database content from notebooks or scopes the attacker was never authorized to access.
AML.T0037

What systems are affected?

PackageEcosystemVulnerable RangePatched
Jupyter Notebookgo< 0.0.0-20260720151813-0f5a0e7c67b00.0.0-20260720151813-0f5a0e7c67b0
13.5KOpenSSF 5.83.0K dependentsPushed 2d ago79% patched~75d to patchFull package profile →

Do you use Jupyter Notebook? You're affected.

How severe is it?

CVSS 3.1
7.7 / 10
EPSS
0.5%
chance of exploitation in 30 days
Higher than 45% of all CVEs
Exploitation Status
Exploit Available
Exploitation: MEDIUM
Sophistication
Moderate
Exploitation Confidence
medium
○Public PoC indexed (trickest/cve)
Composite signal derived from CISA KEV, VulnCheck KEV, CISA SSVC, EPSS, Metasploit, Exploit-DB, trickest/cve, Nuclei templates, and inthewild.io exploitation reports.

What is the attack surface?

AVACPRUISCIA
AVNetwork
ACLow
PRLow
UINone
SChanged
CHigh
INone
ANone

What should I do?

1 step
  1. Patch to SiYuan kernel build 0.0.0-20260720151813-0f5a0e7c67b0 or later, which moves the ast.IsNodeIDPattern identifier check ahead of path construction (or confines it at the filesystem sink) for all four endpoints. Until patched, set Publish.Auth.Enable to true so the publish service never falls back to the anonymous account, and audit/rotate any existing RoleReader publish tokens, restricting them to trusted external readers only. Detection: monitor kernel/publish access logs for requests to /api/av/renderAttributeView, /api/av/getAttributeViewKeysByID, /api/av/getAttributeViewKeys, or /api/av/getCurrentAttrViewImages where the id/avID parameter contains ../, %2e%2e, or resolves outside storage/av/. Where feasible, place the publish service behind a WAF rule blocking path-traversal sequences in JSON request bodies.

What does CISA's SSVC say?

DecisionTrack
Exploitationnone
AutomatableNo
Technical Impactpartial

Source: CISA Vulnrichment (SSVC v2.0). Decision based on the CISA Coordinator decision tree.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Article 15-Accuracy, Robustness and Cybersecurity
ISO 42001
A.7.5-Data for AI systems - security
OWASP LLM Top 10
LLM06-Sensitive Information Disclosure

Frequently Asked Questions

What is CVE-2026-69086?

SiYuan's attribute-view API endpoints build a filesystem path from a caller-supplied ID and, on the 'file exists' code path, skip identifier validation entirely, letting a `../`-laced avID escape the intended storage directory and force the kernel to read and parse an arbitrary existing `.json` file elsewhere in the workspace. This is reachable by any client holding a low-privilege RoleReader publish token, and when Publish.Auth.Enable is left at its default of false, by a fully anonymous client hitting the public-facing publish service on port 6808 — no admin role or CSRF token required. With 2,997 downstream dependents and 40 other CVEs already recorded against this package, the blast radius among SiYuan self-hosted knowledge bases is real, though the EPSS score of 0.35% (72nd percentile) and absence from CISA KEV or public exploit code suggest exploitation isn't yet trending. The primary risk is confidentiality only (CVSS 7.7, C:H/I:N/A:N): disclosure of attribute-view/database content from notebooks the reader shouldn't see, plus a file-existence oracle for arbitrary `.json` paths. Patch to kernel build 0.0.0-20260720151813-0f5a0e7c67b0 or later, and until then set Publish.Auth.Enable to true and rotate or restrict any RoleReader publish tokens to trusted parties.

Is CVE-2026-69086 actively exploited?

Proof-of-concept exploit code is publicly available for CVE-2026-69086, increasing the risk of exploitation.

How to fix CVE-2026-69086?

Patch to SiYuan kernel build 0.0.0-20260720151813-0f5a0e7c67b0 or later, which moves the ast.IsNodeIDPattern identifier check ahead of path construction (or confines it at the filesystem sink) for all four endpoints. Until patched, set Publish.Auth.Enable to true so the publish service never falls back to the anonymous account, and audit/rotate any existing RoleReader publish tokens, restricting them to trusted external readers only. Detection: monitor kernel/publish access logs for requests to /api/av/renderAttributeView, /api/av/getAttributeViewKeysByID, /api/av/getAttributeViewKeys, or /api/av/getCurrentAttrViewImages where the id/avID parameter contains `../`, `%2e%2e`, or resolves outside storage/av/. Where feasible, place the publish service behind a WAF rule blocking path-traversal sequences in JSON request bodies.

What systems are affected by CVE-2026-69086?

This vulnerability affects the following AI/ML architecture patterns: RAG pipelines, knowledge base / notebook storage.

What is the CVSS score for CVE-2026-69086?

CVE-2026-69086 has a CVSS v3.1 base score of 7.7 (HIGH). The EPSS exploitation probability is 0.53%.

What is the AI security impact?

Affected AI Architectures

RAG pipelinesknowledge base / notebook storage

MITRE ATLAS Techniques

AML.T0036Data from Information Repositories
AML.T0037Data from Local System
AML.T0049Exploit Public-Facing Application

Compliance Controls Affected

EU AI Act: Article 15
ISO 42001: A.7.5
OWASP LLM Top 10: LLM06

What are the technical details?

Original Advisory

**CVE:** This vulnerability corresponds to [CVE-2026-69086](https://nvd.nist.gov/vuln/detail/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) { // <-- ONLY id guard, create branch only return ErrInvalidID } // ... create ... } attrView, err = av.ParseAttributeView(avID) // LOAD runs unconditionally ``` When the traversal `avID` resolves to a file that already exists, the `!filelock.IsExist(...)` condition is `false`, the entire block (including the line with `ast.IsNodeIDPattern`) is skipped, and control falls straight through to `av.ParseAttributeView(avID)`. That function rebuilds the path via `filepath.Join(DataDir, "storage", "av", avID+".json")` and calls `filelock.ReadFile` with no `filepath.Rel` / `IsSubPath` / `..` rejection: ```go // av.ParseAttributeView -> 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.

Exploitation Scenario

An attacker discovers an internet-exposed SiYuan publish instance on the default port 6808 — for example, a team using SiYuan's publish feature to share a curated knowledge base externally. If the operator left Publish.Auth.Enable at its default false, the attacker connects anonymously; otherwise they use any low-privilege RoleReader token issued for legitimate read access to one notebook. They send a POST to /api/av/renderAttributeView with an id value built from `../` segments that resolves to an existing .json file elsewhere in the workspace — for instance, an attribute-view file belonging to a different, non-public notebook. Because that file already exists, SiYuan's identifier-validation check (nested only inside the 'not-exist/create' branch) never runs, and the kernel reads and parses the file, returning its attribute-view content to the attacker even though they were never authorized to see that notebook or scope.

Weaknesses (CWE)

CWE-22 — Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal'): The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

  • [Implementation] Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does. When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue." Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylis
  • [Architecture and Design] For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N

Timeline

Published
September 3, 2026
Last Modified
September 3, 2026
First Seen
September 4, 2026

Related Vulnerabilities