# SiYuan Vulnerable to Path Traversal in /export Endpoint Allows Arbitrary File Read and Secret Leakage

Double-encoded traversal in SiYuan's /export endpoint plus wildcard CORS lets any website read localhost files like conf/conf.json, leaking API tokens and auth codes.

- Payout: Research
- Severity: critical
- Program: SiYuan
- Found by: Zwique
- Disclosed: 2026-03-07
- CVE: CVE-2026-30869
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-2h2p-mvfx-868w
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-2h2p-mvfx-868w
- Tags: area:web domain:web impact:data-leak kind:research platform:ghsa sev:critical tech:go technique:source-review vuln:auth-bypass vuln:cors vuln:info-disclosure vuln:path-traversal

**Target:** /export endpoint of SiYuan kernel HTTP server
**Root cause:** The /export handler url.PathUnescape's the path and filepath.Join's it under exportBaseDir without verifying containment, so double-encoded %252e%252e survives ServeFile's dot-dot rejection and decodes to ../ after routing. Localhost requests to /export/* are also auto-granted admin, and CORS is wildcarded.
**Steps:**
1. Send `GET /export/%252e%252e/%252e%252e/conf/conf.json` (or deeper traversal to `/etc/passwd`) to the SiYuan kernel
2. On HTTP 200, read response body for `api.token`, `cookieKey`, `accessAuthCode`
3. Use leaked token: `POST /api/system/getNetwork` with `Authorization: Token <leaked token>`
4. Confirm admin-level response
**How found:** Code review of session.go auth middleware and serve.go export handler: noticed url.PathUnescape applied after routing, filepath.Join without containment check, localhost admin bypass for /export/*, and global wildcard CORS — combined into a cross-origin localhost file read.
**Exploitation:** Attacker hosts a malicious page; victim's browser on 127.0.0.1 is induced to fetch the traversal URL against the local SiYuan instance. Wildcard `Access-Control-Allow-Origin: *` lets the page read the response, exfiltrating conf/conf.json secrets (API token, cookieKey, accessAuthCode) cross-origin. Leaked token then grants admin kernel API access, potentially chained to RCE.
**Escalation:** Leaked api.token/cookieKey/accessAuthCode -> authenticated admin API calls -> potential RCE via other kernel features.
**Insight:** When a handler decodes a path AFTER the router/ServeFile has already rejected dot-dot, double-encoding (%252e%252e) slips through; check for unescape-then-join patterns and pair with wildcard CORS to turn localhost-only services into cross-origin file reads.

## Proof of concept (copied exactly from the original report)

**Double-encoded traversal request to read conf.json**

```
Send a GET request to `/export/%252e%252e/%252e%252e/conf/conf.json` or `export/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/etc/passwd
```

**Admin API test with leaked token**

```
POST /api/system/getNetwork
Header: Authorization: Token <leaked token>

4. Confirm that the response indicates administrative privileges.
```

