CVE-2026-31807

CVE-2026-31807 is a medium-severity cross-site scripting (XSS) vulnerability in github.com/siyuan-note/siyuan/kernel (go), affecting versions < 0.0.0-20260310025236-297bd526708f. It is fixed in 0.0.0-20260310025236-297bd526708f.

Summary

SVG Sanitizer Bypass via <animate> Element, Unauthenticated XSS

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)

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)

// 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:

<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

Untrusted input is rendered as active markup in a victim's browser, which can run script in their session. Typical impact: session or credential theft, and actions taken as the user.

Affected versions

github.com/siyuan-note/siyuan/kernel (< 0.0.0-20260310025236-297bd526708f)

Security releases

github.com/siyuan-note/siyuan/kernel → 0.0.0-20260310025236-297bd526708f (go)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

See it in your environment

Remediation advice

Add animation elements to the sanitizer blocklist:

// 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:

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.

Frequently Asked Questions

  1. What is CVE-2026-31807? CVE-2026-31807 is a medium-severity cross-site scripting (XSS) vulnerability in github.com/siyuan-note/siyuan/kernel (go), affecting versions < 0.0.0-20260310025236-297bd526708f. It is fixed in 0.0.0-20260310025236-297bd526708f. Untrusted input is rendered as active markup in a victim's browser, which can run script in their session.
  2. Which versions of github.com/siyuan-note/siyuan/kernel are affected by CVE-2026-31807? github.com/siyuan-note/siyuan/kernel (go) versions < 0.0.0-20260310025236-297bd526708f is affected.
  3. Is there a fix for CVE-2026-31807? Yes. CVE-2026-31807 is fixed in 0.0.0-20260310025236-297bd526708f. Upgrade to this version or later.
  4. Is CVE-2026-31807 exploitable, and should I be worried? Whether CVE-2026-31807 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  5. What actually determines whether CVE-2026-31807 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  6. How do I fix CVE-2026-31807? Upgrade github.com/siyuan-note/siyuan/kernel to 0.0.0-20260310025236-297bd526708f or later.

Other vulnerabilities in github.com/siyuan-note/siyuan/kernel

CVE-2026-45375CVE-2026-45371CVE-2026-45148CVE-2026-45147CVE-2026-44588

Stop the waste.
Protect your environment with Kodem.