SiYuan vulnerable to reflected XSS via SVG namespace prefix bypass in SanitizeSVG (getDynamicIcon, unauthenticated)
Date: 2026-04
Affected: go/github.com/siyuan-note/siyuan/kernel
Attack vector: xss
Category: vulnerability-disclosure
Severity: Critical
CVE: CVE-2026-34448
CVE-2026-34585
CVE-2026-34605
CWE: CWE-79
CWE-94
CVSS: 6.1 (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N)

### Summary The `SanitizeSVG` function introduced in v3.6.0 to fix XSS in the unauthenticated `/api/icon/getDynamicIcon` endpoint can be bypassed by using namespace-prefixed element names such as `<x:script xmlns:x="http://www.w3.org/2000/svg">`. The Go HTML5 parser records the element's tag as `"x:script"` rather than `"script"`, so the tag check passes it through. The SVG is served with `Content-Type: image/svg+xml` and no Content Security Policy; when a browser opens the response directly, its XML parser resolves the prefix to the SVG namespace and executes the embedded script. ### Details The `getDynamicIcon` route is registered without authentication: ```go // kernel/server/serve.go ginServer.Handle("GET", "/api/icon/getDynamicIcon", getDynamicIcon) ``` For type 8, the `content` query parameter is inserted directly into an SVG `<text>` element using `fmt.Sprintf` with no HTML encoding: ```go // kernel/api/icon.go:579-584 return fmt.Sprintf(` <svg id="dynamic_icon_type8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> <path d="..."/> <text x="50%%" y="55%%" ...>%s</text> </svg>`, ..., content) ``` `SanitizeSVG` then parses the SVG with `github.com/88250/lute/html` and removes elements whose lowercased tag name matches a fixed list: ```go // kernel/util/misc.go:249-252 tag := strings.ToLower(c.Data) if tag == "script" || tag == "iframe" || tag == "object" || tag == "embed" || tag == "foreignobject" || "animate" == tag || ... {


Mitigations:

Architectural layers (MAESTRO):