CSIRTS // UNIFIED SECURITY ADVISORY FEEDSYS ● ONLINE · POWERED BY INTELFUSIONS.COM

GHSA-p4m3-mgmm-c664: SiYuan: Path Traversal via Double URL Encoding in /assets/*path (publish mode arbitrary file─read), Incomplete fix of CVE-2026-41894

highCVSS 7.5CVE-2026-54066
Summary The patch for CVE-2026-41894 ("Path Traversal via Double URL Encoding") sanitized the /export/ route but the **identical root cause remains in the /assets/*path route. In publish mode (anonymous read-only HTTP endpoint, default port 6808), an unauthenticated remote attacker can read arbitrary files inside WorkspaceDir — including conf/conf.json (which contains the AccessAuthCode SHA256 hash, API token, and sync keys), temp/siyuan.db, temp/blocktree.db, and siyuan.log — by double-URL-encoding .. segments. Verified against siyuan v3.6.5: - GET /assets/%252e%252e/%252e%252e/conf/conf.json → HTTP 200, 10349 bytes (conf.json served) - GET /export/%252e%252e/%252e%252e/conf/conf.json → HTTP 401 (patched) - GET /assets/%2e%2e/conf/conf.json → HTTP 404 (single-decode handled correctly) Vulnerable Code Step 1 — route & first decode** (kernel/server/serve.go:587-626): The router registers GET /assets/*path for the publish listener. Gin performs one URL decoding pass on URL.Path, so a request for /assets/%252e%252e/... yields context.Param("path") == "/%2e%2e/%2e%2e/conf/conf.json" — literal %2e%2e strings, which path.Clean cannot collapse. Step 2 — second decode via fallback (kernel/model/assets.go:536-563, GetAssetAbsPath): p, err := getAssetAbsPath(relativePath) if nil != err { // fallback decoded, e := url.PathUnescape(relativePath) // ← line 548, second decode if nil == e { p, err = getAssetAbsPath(decoded) } } After the fallback decodes %2e%2e to .., filepath.Join(DataDir, "../../conf/conf.json") is Clean-ed to WorkspaceDir/conf/conf.json, an existing file. Step 3 — publish-mode access gate fall-through (kernel/model/publish_access.go:288, CheckAbsPathAccessableByPublishAccess): if !filelock.IsSubPath(util.DataDir, absPath) { return true // ← fall-through allows anything outside DataDir but inside WorkspaceDir } Because the resolved file is *outside* DataDir (it's in WorkspaceDir), the gate returns true and IsSensitivePath() is never invoked — .db / .

Details

Source
GitHub Security Advisories (INTL · database · site)
Severity
high — CVSS 7.5
Published
2026-07-10
Last updated
2026-07-10
Exploitation
Not in CISA KEV at last sync

Original advisory: https://github.com/advisories/GHSA-p4m3-mgmm-c664

Exploitation outlook

EPSS (FIRST.org) estimates each CVE’s probability of exploitation in the next 30 days — here is the CSIRTS.com read on those numbers.

Referenced CVEs

CVECSIRTS overviewExternal
CVE-2026-54066coverage & exploitation statusNVD · CVE.org

More from GitHub Security Advisories