SiYuan, Stored XSS to RCE, Critical

Listen to this Post

How the CVE works:

The vulnerability stems from missing HTML escaping of the `name` and `version` fields in SiYuan’s marketplace package manifests (plugin.json, theme.json, etc.). The kernel-side function `sanitizePackageDisplayStrings` in `kernel/bazaar/package.go` escapes only Author, DisplayName, and Description, leaving Name and Version raw. The frontend in `app/src/config/bazaar.ts` injects these fields into HTML template strings (e.g., ${item.preferredName}) and assigns them to innerHTML. A malicious payload embedded in `name` or `version` executes as DOM XSS when a user opens Settings → Marketplace → Downloaded → Plugins (zero‑click). Because the Electron desktop client has nodeIntegration: true, contextIsolation: false, and `webSecurity: false` (app/electron/main.js:407-411), the XSS gains full Node.js access, enabling arbitrary OS command execution via require('child_process').exec. The `preferredName` fallback (when `displayName` is empty) returns the unescaped pkg.Name, ensuring the payload reaches the renderer even without a displayed locale. The online marketplace path also skips kernel sanitization; the GitHub‑Action workflow (siyuan-note/bazaar/actions/stage/main.go) mirrors the same flaw, leaving Name and Version unescaped. An attacker submits a malicious `plugin.json` to the public bazaar, and every client fetching the listing is affected. The payload can be visually hidden with display:none, making the plugin card appear legitimate. The attack requires no interaction beyond opening the marketplace tab.

dailycve form:

Platform: SiYuan desktop
Version: v3.6.5
Vulnerability: Stored XSS→RCE
Severity: Critical
date: 2026-05-13

Prediction: 2026-05-27

What Undercode Say:

Check unescaped name field in API response
curl -s -X POST http://127.0.0.1:16806/api/bazaar/getInstalledPlugin \
-H 'Content-Type: application/json' -d '{"frontend":"desktop","keyword":""}' \
| jq '.packages[bash].preferredName'
Grep for missing escapes in kernel source
grep -A10 "func sanitizePackageDisplayStrings" kernel/bazaar/package.go
Verify Electron insecure settings
grep -E "nodeIntegration|contextIsolation|webSecurity" app/electron/main.js

Exploit:

{
"name": "Markdown Utilities<img src=x onerror=\"require('child_process').exec('calc')\" style=\"display:none\">",
"displayName": {},
"description": {"default": "Helpful tools"},
"author": "attacker",
"version": "1.0.0"
}

Place in /data/plugins/evil/plugin.json. Open Settings → Marketplace → Downloaded → Plugins → calculator spawns.

Protection from this CVE:

  • Extend `sanitizePackageDisplayStrings` to escape pkg.Name, pkg.Version, and pkg.Keywords.
  • Call sanitization in `buildBazaarPackageWithMetadata` (online path).
  • Wrap frontend sinks with `escapeHtml()` in bazaar.ts.
  • Enable `contextIsolation: true` with a preload bridge in Electron.

Impact:

Arbitrary OS command execution under victim’s account, full filesystem and network access, triggered by viewing marketplace tab, undetectable payload, persists across sync and export.

🎯Let’s Practice Exploiting & Learn Patching For Free:

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top