GHSA-5hc8-qmg8-pw27: SiYuan has a SVG Sanitizer Bypass via `<animate>` Element — Unauthenticated XSS
SVG Sanitizer Bypass via `<animate>` Element — Unauthenticated XSSSummarySiYuan's SVG sanitizer (`SanitizeSVG`) blocks dangerous elements (`<script>`, `<iframe>`, `<foreignobject>`) and removes `on*` event handlers and `javascript:` in `href` attributes. However, it does NOT block SVG animation elements (`<animate>`, `<set>`) which can dynamically set attributes to dangerous values at runtime, bypassing the static sanitization. This allows an attacker to inject executable JavaScript into the unauthenticated `/api/icon/getDynamicIcon` endpoint (type=8), creating a reflected XSS.This is a bypass of the fix for CVE-2026-29183 (fixed in v3.5.9).Affected Component**File:** `kernel/util/misc.go`**Function:** `SanitizeSVG()` (lines 234-319)**Endpoint:** `GET /api/icon/getDynamicIcon?type=8&content=...` (unauthenticated)**Version:** SiYuan <= 3.5.9Root CauseThe sanitizer checks attributes on elements at **parse time**. SVG `<animate>` and `<set>` elements modify attributes **at runtime** — these elements are not in the sanitizer's blocklist.Sanitizer's blocklist (line 250)Missing from blocklist: `animate`, `set`, `animateTransform`, `animateMotion`Attribute check (lines 264-267)The `<animate>` element's `values` attribute contains the payload (`javascript:...`), but the sanitizer only checks for `on*` prefix, `href`, or `xlink:href` keys. The `values`, `to`, `from`, `attributeName` attributes are all passed through.Proof of ConceptVector 1: `<animate>` sets `href` to `javascript:`After template rendering, the SVG contains:The sanitizer passes this through because:`<animate>` is not in the element blocklist`attributeName="href"` — key is `attributename`, doesn't start with `on`, not `href` itself`values="javascript:..."` — key is `values`, not `href`When the SVG is rendered in the browser (navigating directly to the URL), `<animate>` sets the parent `<a>` element's `href` to `javascript:alert(document.domain)`. Clicking "Click me" triggers the JavaScript.Vector 2: `<set>` modifies event handlersThe `<set>` element dynamically adds an `onmouseover` event handler to the parent element at runtime.Attack ScenarioAttacker crafts a malicious `getDynamicIcon` URL with XSS payloadAttacker sends the URL to a victim who has an active SiYuan sessionVictim clicks/navigates to the URLSVG renders with Content-Type `image/svg+xml` — browser renders as standalone SVG documentJavaScript executes in the SiYuan server's originAttacker steals session cookies, API tokens, or makes authenticated API calls to read/modify notesImpact**Severity:** CRITICAL (CVSS ~9.1)**Type:** CWE-79 (Improper Neutralization of Input During Web Page Generation)Unauthenticated reflected XSS via SVG injectionExecutes in the SiYuan application origin, giving full access to authenticated APIsCan chain to: data exfiltration, note modification, configuration theft (API tokens, auth codes)Bypasses the fix for CVE-2026-29183Suggested FixAdd animation elements to the sanitizer blocklist:Or additionally check the `values`, `to`, and `from` attributes for `javascript:` patterns:Also consider checking `attributeName` — if it targets `href`, `xlink:href`, or any `on*` attribute, the animation element should be removed entirely.
CVSS v4.0: 6.4