VYPR
Critical severityNVD Advisory· Published Mar 6, 2026· Updated Mar 6, 2026

SiYuan: Unauthenticated reflected SVG XSS in `/api/icon/getDynamicIcon` (`type=8`) enables arbitrary JavaScript execution

CVE-2026-29183

Description

SiYuan is a personal knowledge management system. Prior to version 3.5.9, an unauthenticated reflected XSS vulnerability exists in the dynamic icon API endpoint "GET /api/icon/getDynamicIcon" when type=8, attacker-controlled content is embedded into SVG output without escaping. Because the endpoint is unauthenticated and returns image/svg+xml, a crafted URL can inject executable SVG/HTML event handlers (for example onerror) and run JavaScript in the SiYuan web origin. This can be chained to perform authenticated API actions and exfiltrate sensitive data when a logged-in user opens the malicious link. This issue has been patched in version 3.5.9.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/siyuan-note/siyuan/kernelGo
< 0.0.0-20260304034809-d68bd5a793910.0.0-20260304034809-d68bd5a79391

Affected products

1

Patches

1
d68bd5a79391

:lock: https://github.com/siyuan-note/siyuan/security/advisories/GHSA-6865-qjcf-286f

https://github.com/siyuan-note/siyuanDanielMar 4, 2026via ghsa
3 files changed · +56 9
  • kernel/api/icon.go+1 1 modified
    @@ -165,7 +165,7 @@ func getDynamicIcon(c *gin.Context) {
     	}
     
     	if !model.Conf.Editor.AllowSVGScript {
    -		svg = util.RemoveScriptsInSVG(svg)
    +		svg = util.SanitizeSVG(svg)
     	}
     
     	c.Header("Content-Type", "image/svg+xml")
    
  • kernel/server/serve.go+1 1 modified
    @@ -618,7 +618,7 @@ func serveSVG(context *gin.Context, assetAbsPath string) bool {
     		}
     
     		if !model.Conf.Editor.AllowSVGScript {
    -			data = []byte(util.RemoveScriptsInSVG(string(data)))
    +			data = []byte(util.SanitizeSVG(string(data)))
     		}
     
     		context.Data(200, "image/svg+xml", data)
    
  • kernel/util/misc.go+54 7 modified
    @@ -231,8 +231,7 @@ func ReplaceStr(strs []string, old, new string) (ret []string, changed bool) {
     	return
     }
     
    -// RemoveScriptsInSVG 移除 SVG 中的 <script> 标签及其内部所有内容
    -func RemoveScriptsInSVG(svgInput string) string {
    +func SanitizeSVG(svgInput string) string {
     	// 1. 将字符串解析为节点树
     	doc, err := html.Parse(strings.NewReader(svgInput))
     	if err != nil {
    @@ -246,13 +245,61 @@ func RemoveScriptsInSVG(svgInput string) string {
     		// 倒序遍历子节点,确保删除操作不影响后续迭代
     		for c := n.FirstChild; c != nil; {
     			next := c.NextSibling
    -			// 检查标签名是否为 script
    -			if c.Type == html.ElementNode && strings.EqualFold(c.Data, "script") {
    -				n.RemoveChild(c)
    -			} else {
    -				// 递归处理子节点
    +			if c.Type == html.ElementNode {
    +				tag := strings.ToLower(c.Data)
    +				if tag == "script" || tag == "iframe" || tag == "object" || tag == "embed" || tag == "foreignobject" {
    +					n.RemoveChild(c)
    +					c = next
    +					continue
    +				}
    +
    +				// 清理不安全属性
    +				if len(c.Attr) > 0 {
    +					// 过滤属性:删除以 on 开头的属性(事件处理),href/xlink:href 指向 javascript: 或不安全 data:,以及危险的 style 表达式
    +					filtered := c.Attr[:0]
    +					for _, a := range c.Attr {
    +						key := strings.ToLower(a.Key)
    +						val := strings.TrimSpace(strings.ToLower(a.Val))
    +
    +						// 删除事件处理器属性(onload, onerror 等)
    +						if strings.HasPrefix(key, "on") {
    +							continue
    +						}
    +
    +						// 删除 href 或 xlink:href 指向 javascript: 或某些不安全的 data: URI
    +						if key == "href" || key == "xlink:href" || key == "xlinkhref" {
    +							if strings.HasPrefix(val, "javascript:") {
    +								continue
    +							}
    +							// 对 data: 做保守处理,删除包含可执行内容的 data:text/html 或 data:image/svg+xml
    +							if strings.HasPrefix(val, "data:") {
    +								if strings.Contains(val, "text/html") || strings.Contains(val, "image/svg+xml") || strings.Contains(val, "application/xhtml+xml") {
    +									continue
    +								}
    +							}
    +						}
    +
    +						// 清理 style 中的危险表达式,如 expression() 或 url(javascript:...)
    +						if key == "style" {
    +							low := val
    +							if strings.Contains(low, "expression(") || strings.Contains(low, "url(javascript:") || strings.Contains(low, "javascript:") {
    +								// 丢弃整个 style 属性以保证安全
    +								continue
    +							}
    +						}
    +
    +						// 其它属性保留
    +						filtered = append(filtered, a)
    +					}
    +					c.Attr = filtered
    +				}
    +			}
    +
    +			// 递归处理子节点(如果节点尚未被删除)
    +			if c.Parent != nil {
     				walk(c)
     			}
    +
     			c = next
     		}
     	}
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.