CSIRTS // UNIFIED SECURITY ADVISORY FEEDSYS ● ONLINE · POWERED BY INTELFUSIONS.COM

GHSA-mvjr-vv3c-w4qv: SiYuan: Stored XSS to RCE via CSS-snippet breakout in renderSnippet()

criticalCVSS 9.9CVE-2026-54067
Summary A CSS snippet body containing </style> breaks out of its surrounding <style> tag when renderSnippet() interpolates it via insertAdjacentHTML. A payload like </style><img src=x onerror="..."> runs arbitrary JavaScript in the renderer. On Electron desktop builds the renderer runs with nodeIntegration:true, so require('child_process') is reachable from the injected handler and the XSS chains to host RCE. Snippets sync via the workspace repository, so an attacker with write access to any synced workspace plants the payload once and it fires on every device that pulls. The bug also bypasses the user's enabledCSS / enabledJS separation. A user who turned enabledJS off was making a deliberate call not to run untrusted JavaScript; the CSS path runs it anyway. Details Affected: - HEAD 96dfe0b (v3.6.5, 2026-04-21) - Sink: app/src/config/util/snippets.ts:32 - Source: /api/snippet/getSnippet, backed by data/snippets/conf.json - Default config: EnabledCSS: true, EnabledJS: true at kernel/conf/snippet.go:26-27 - Electron config: nodeIntegration:true, contextIsolation:false, webSecurity:false on every BrowserWindow in app/electron/main.js:307,408-411,1107-1110,1150-1153,1322 The write path stores raw content. kernel/api/snippet.go:107-130 copies Content from the request straight into the snippet record with no HTML escape, no </style> check, no type-specific validation: snippet := &conf.Snippet{ ID: m["id"].(string), Name: m["name"].(string), Type: m["type"].(string), Content: m["content"].(string), Enabled: m["enabled"].(bool), } Storage is workspace-internal and syncs. kernel/model/repository.go:1748,1798 reference data/snippets/conf.json, so the malicious record propagates to every sync peer. The renderer reads the snippet back through /api/snippet/getSnippet and interpolates it into a <style> tag, raw. app/src/config/util/snippets.ts:32, called on app boot and on the reloadSnippet WebSocket event: fetchPost("/api/snippet/getSnippet", {type: "all", enabled: 2}

Details

Source
GitHub Security Advisories (INTL · database · site)
Severity
critical — CVSS 9.9
Published
2026-07-10
Last updated
2026-07-10
Exploitation
Not in CISA KEV at last sync

Original advisory: https://github.com/advisories/GHSA-mvjr-vv3c-w4qv

Exploitation outlook

EPSS (FIRST.org) estimates each CVE’s probability of exploitation in the next 30 days — here is the CSIRTS.com read on those numbers.

Referenced CVEs

CVECSIRTS overviewExternal
CVE-2026-54067coverage & exploitation statusNVD · CVE.org

More from GitHub Security Advisories