{"record":{"id":"a2abd04c6598a210","repo":"siyuan-note/siyuan","slug":"svg-directives-are-not-allowed","errorCode":null,"errorMessage":"svg directives are not allowed","messagePattern":"svg directives are not allowed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/misc.go","lineNumber":441,"sourceCode":"\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (!rootSeen || rootClosed) && strings.TrimSpace(string(typed)) != \"\" {\n\t\t\t\treturn \"\", fmt.Errorf(\"svg contains text outside the root element\")\n\t\t\t}\n\t\t\tif rootSeen && !rootClosed {\n\t\t\t\tif err = encoder.EncodeToken(typed); err != nil {\n\t\t\t\t\treturn \"\", fmt.Errorf(\"render svg failed: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\tcase xml.Comment:\n\t\t\tif skipDepth == 0 && rootSeen && !rootClosed {\n\t\t\t\tif err = encoder.EncodeToken(typed); err != nil {\n\t\t\t\t\treturn \"\", fmt.Errorf(\"render svg failed: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\tcase xml.Directive:\n\t\t\tif !isBenignSVGDoctype(string(typed)) {\n\t\t\t\treturn \"\", fmt.Errorf(\"svg directives are not allowed\")\n\t\t\t}\n\t\t\t// 良性 DOCTYPE 声明不写入输出，与 XML 声明（ProcInst）的处理方式一致，不影响浏览器渲染\n\t\tcase xml.ProcInst:\n\t\t\t// XML 声明和处理指令不影响 SVG 图像内容，输出时统一省略。\n\t\t}\n\t}\n\n\tif !rootSeen || !rootClosed || depth != 0 || skipDepth != 0 || len(elementStack) != 0 {\n\t\treturn \"\", fmt.Errorf(\"svg root element is incomplete\")\n\t}\n\tif err := encoder.Close(); err != nil {\n\t\treturn \"\", fmt.Errorf(\"render svg failed: %w\", err)\n\t}\n\treturn buf.String(), nil\n}\n\nfunc preserveXMLName(name xml.Name) xml.Name {\n\tif name.Space != \"\" {","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/misc.go#L423-L459","documentation":"The input contains an XML directive (the token between '<!' and '>' — usually a DOCTYPE) that is not a benign, subset-free SVG DOCTYPE. Internal DTD subsets can declare entities (XXE / billion-laughs style attacks and entity expansion tricks), so SanitizeSVG hard-rejects any directive whose body fails isBenignSVGDoctype (anything with an internal subset '[...]' or non-svg root name).","triggerScenarios":"DOCTYPE with an internal subset: '<!DOCTYPE svg [ <!ENTITY xxe SYSTEM \"file:///etc/passwd\"> ]>'; a DOCTYPE naming a root other than svg; any other <!...> directive token; referencing external DTDs.","commonSituations":"SVGs copied from document-generation pipelines (Word, Inkscape with DTD output) that carry DOCTYPE declarations; legacy icon sets authored against SVG 1.1 DTD validation; malicious uploads attempting XXE.","solutions":["Delete the DOCTYPE declaration entirely — it is optional and never needed for rendering","If DTD validation metadata matters, keep it in a separate file and ship only the bare <svg> markup","For batch processing, strip directives with a regex on '<!DOCTYPE' ... '>' before calling SanitizeSVG","Never re-enable entity declarations; expand any entities in text content to literal characters beforehand"],"exampleFix":"// before\nSanitizeSVG(\"<!DOCTYPE svg [<!ENTITY x \\\"y\\\">]><svg>...</svg>\") // svg directives are not allowed\n// after\nSanitizeSVG(\"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\">...</svg>\")","handlingStrategy":"validation","validationCode":"func stripDOCTYPE(input string) string {\n\ti := strings.Index(input, \"<!DOCTYPE\")\n\tif i < 0 { return input }\n\tj := strings.Index(input[i:], \">\")\n\tif j < 0 { return input }\n\treturn strings.TrimSpace(input[:i] + input[i+j+1:])\n}","typeGuard":"func hasInternalSubset(input string) bool {\n\ti := strings.Index(strings.ToUpper(input), \"<!DOCTYPE\")\n\treturn i >= 0 && strings.Contains(input[i:], \"[\") && strings.Contains(input[i:], \"]\")\n}","tryCatchPattern":"clean, err := util.SanitizeSVG(input)\nif err != nil && strings.Contains(err.Error(), \"directives are not allowed\") {\n\tinput = stripDOCTYPE(input)\n\tclean, err = util.SanitizeSVG(input)\n}\nif err != nil { return err }","preventionTips":["Export icons without DOCTYPE/DTD references","Resolve any named entities to literal characters before sanitizing","Treat DOCTYPE with internal subsets as hostile input (XXE risk)","Add a lint rule that fails CI when icon assets contain '<!DOCTYPE'"],"tags":["svg","xml","xxe","security","sanitization"],"backgroundTag":"schema-validation-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}