Executive brief
SiYuan is a note-taking and knowledge management application that processes user-supplied SVG files. The SVG sanitizer fails to properly remove malicious scripts hidden within certain XML tags, allowing attackers to inject JavaScript that executes in the application's security context. An authenticated attacker can exploit this through either a crafted link (reflected XSS) or by planting a malicious SVG file as an asset (stored XSS), potentially stealing API tokens, reading/modifying notes, or achieving full workspace takeover on desktop installations.
Technical details
The vulnerability exists in the `util.SanitizeSVG` function (kernel/util/misc.go:319) which uses an HTML parser to sanitize SVG content before serving it inline as `image/svg+xml`. The root cause is a mismatch between how the HTML parser treats certain tags versus how browsers interpret them as XML/SVG. Specifically, HTML integration points like `<desc>` and `<title>`, and raw text elements like `<style>`, `<xmp>`, and `<noscript>` are parsed differently—the HTML parser treats content inside `<style>` as plain text and does not traverse child nodes, so embedded `<script>` tags are never seen and thus never removed. When the same content is served and interpreted as SVG/XML, these tags are treated as normal elements, and the hidden script becomes executable. The vulnerability can be exploited via two attack vectors: (1) reflected XSS through the `/api/icon/getDynamicIcon` endpoint with `type=8`, where the `content` parameter is reflected unsanitized into an SVG template, and (2) stored XSS by placing a malicious SVG file in the assets directory. Both require authentication (CheckAuth allows Administrator, Editor, and Reader roles) and user interaction (opening a link or navigating to an asset). Exploitation allows arbitrary JavaScript execution in the app origin, enabling API calls to read/write notes, access configuration, and steal API tokens.
Affected products
- SiYuan SiYuan < 0.0.0-20260714095344-f08dee71ba8e (patched in v3.7.3)
Timeline
- 2026-07-14: disclosed: Published to GitHub Advisory Database
- 2026-07-14: patched: Patch released in commit f08dee71ba8e, v3.7.3