CVE-2026-41894High▾ TwilightSiYuan: Path Traversal via Double URL Encoding in `/export/` Endpoint (Incomplete Fix Bypass for CVE-2026-30869)
▾ Twilight zone — High severity, or a signal on a lesser flaw
impact 41.3 · likelihood 0.1 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
Disclosure to exploitation, from the record and what we observed since indexing it.
Disclosed via GHSA
Last analysed / modified upstream
0.4%
The fix for CVE-2026-30869 in SiYuan v3.5.10 only added a denylist check (IsSensitivePath) but did not address the root cause — a redundant url.PathUnescape() call in serveExport(). An authenticated attacker can use double URL encoding (%252e%252e) to traverse directories and read arbitrary workspace files including the full SQLite database (siyuan.db), kernel log, and all user documents.
In kernel/server/serve.go, the serveExport() function (line 314-320) processes file paths as follows:
filePath := strings.TrimPrefix(c.Request.URL.Path, "/export/")
decodedPath, err := url.PathUnescape(filePath) // second decode
fullPath := filepath.Join(exportBaseDir, decodedPath)
Go's HTTP server already decodes percent-encoded characters once during request parsing. The additional url.PathUnescape() call creates a double-decode vulnerability:
GET /export/%252e%252e/siyuan.db%25 → %, result: URL.Path = /export/%2e%2e/siyuan.db%2e%2e as literal characters (not ..), no redirect occursurl.PathUnescape("%2e%2e") decodes to ..filepath.Join(exportBaseDir, "../siyuan.db") resolves to <workspace>/temp/siyuan.dbThe CVE-2026-30869 fix added IsSensitivePath() which blocks <workspace>/conf/ and OS-level paths (/etc, /root, etc.). However, it does NOT block:
<workspace>/temp/siyuan.db — full document database<workspace>/temp/blocktree.db — block tree database<workspace>/temp/siyuan.log — kernel log<workspace>/temp/asset_content.db — asset content databaseNote: the /appearance/ handler in the same file correctly uses gulu.File.IsSubPath() to validate paths (line 447), but this check is missing from the /export/ handler.
poc.zip Please extract the uploaded compressed file before proceeding
siyuan.log) leaks internal server paths, versions, configuration details, and error messages.github.com/siyuan-note/siyuan/kernel < 3.6.5Upgrade to a patched release:
github.com/siyuan-note/siyuan/kernel 3.6.5Connected by shared product, vendor, weakness, or advisory.
CVE-2026-30869Critical· 9.3SiYuan Vulnerable to Path Traversal in /export Endpoint Allows Arbitrary File Read and Secret Leakage
CVE-2026-33194Medium· 6.8SiYuan has an Incomplete Fix for IsSensitivePath Denylist Allows File Read from /opt, /usr, /home (GHSA-h5vh-m7fg-w5h6 Bypass)
GHSA-p23f-cm6q-2qp8Medium· 5.7SiYuan MCP asset.upload Reads Arbitrary Absolute File Paths (Workspace Boundary Bypass)
CVE-2026-69086High· 7.7SiYuan: Path Traversal via unvalidated avID in RenderAttributeView/AV read endpoints : reader-reachable cross-scope attribute-view disclo…
GHSA-gw25-m53r-qh88Medium· 6.5SiYuan: path traversal via /export/temp/ short-circuit branch (incomplete fix for the export-disclosure hardening, GHSA-6865-qjcf-286f)
CVE-2026-59832High· 7.7Siyuan: Authenticated path traversal in /snippets/ static handler (serveSnippets) leaks conf/conf.json secrets and siyuan.db