# SiYuan: SQL injection in backlink/mention search via unescaped stored and client input (publish mode): first-order (client keyword) and second-order (stored document title) breakout on read-write handle

SiYuan backlink/mention MATCH query concatenates client keyword and stored document metadata with only double-quote escaping, letting a single quote inject SQL on the read-write handle.

- Payout: Research
- Severity: critical
- Program: SiYuan
- Found by: Shirshakhtml
- Disclosed: 2026-09-03
- CVE: CVE-2026-72811
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-q2vg-7qgx-x5fc
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-q2vg-7qgx-x5fc
- Tags: area:web domain:oss domain:web impact:data-leak impact:integrity kind:research platform:ghsa sev:critical tech:go technique:source-review vuln:sqli

**Target:** kernel backlink/mention API (getBacklink2 et al.) on siyuan.db
**Root cause:** The backlink/mention MATCH condition in kernel/model/backlink.go concatenates stored block metadata (title/name/alias/anchor) and the client keyword into SQL, escaping only `"` and not `'`, so a single quote breaks out of the string literal. The statement runs on the read-write siyuan.db handle via a driver that loops over `;`-separated statements.
**Steps:**
1. Enable publish mode on port 6808 with publish Basic Auth disabled (anonymous reader).
2. Send `POST http://127.0.0.1:6808/api/ref/getBacklink2` with body `{"id":"<block id>","k":"a'b","mk":""}`.
3. Observe SQL parse error confirming the `'` in keyword breaks out of the literal into SQL context.
4. Second-order: create a document whose title/name/alias contains `'`; it is stored safely by parameterized indexer but appears unescaped in the backlink query when that document participates in a backlink/mention lookup, breaking the query the same way.
**How found:** Code review of query paths reusing stored content: noted indexing INSERTs are parameterized but the backlink/mention MATCH query concatenates stored metadata and client keyword, escaping only `"`. A sweep of other reuse sinks (tag search, virtual refs, IN joins, graph filter) confirmed this is the sole injectable reuse path.
**Exploitation:** Anonymous reader or publish RoleReader supplies a keyword with `'` to getBacklink2, injecting arbitrary SQL into the backlink MATCH query on the read-write handle; statement stacking enables cross-notebook read, write and ATTACH. Second-order: a malicious .sy document delivered via import/sync/shared file detonates when its stored title is concatenated into another kernel's backlink query. PoC limited to syntax-error probe; no exfiltration or write executed.
**Escalation:** Statement stacking on the read-write handle raises impact from read disclosure to arbitrary write and ATTACH; second-order vector extends reach to any kernel that ingests the malicious document.
**Insight:** When auditing an app that parameterizes writes, trace every read path that reuses stored fields — second-order injection hides where storage is safe but query construction concatenates. Also check the driver: a fork that loops over `;`-separated statements turns a read-only sink into write/ATTACH.

