{"record":{"id":"e8a954569abcd8f0","repo":"siyuan-note/siyuan","slug":"svg-nesting-depth-exceeds-d","errorCode":null,"errorMessage":"svg nesting depth exceeds %d","messagePattern":"svg nesting depth exceeds (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/misc.go","lineNumber":370,"sourceCode":"\tfor {\n\t\ttoken, err := decoder.RawToken()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"parse svg failed: %w\", err)\n\t\t}\n\t\ttokenCount++\n\t\tif tokenCount > maxSVGTokens {\n\t\t\treturn \"\", fmt.Errorf(\"svg contains too many tokens\")\n\t\t}\n\n\t\tswitch typed := token.(type) {\n\t\tcase xml.StartElement:\n\t\t\telementStack = append(elementStack, typed.Name)\n\t\t\tdepth++\n\t\t\tif depth > maxSVGDepth {\n\t\t\t\treturn \"\", fmt.Errorf(\"svg nesting depth exceeds %d\", maxSVGDepth)\n\t\t\t}\n\t\t\tif rootClosed {\n\t\t\t\treturn \"\", fmt.Errorf(\"svg contains multiple root elements\")\n\t\t\t}\n\t\t\tif !rootSeen {\n\t\t\t\tif !strings.EqualFold(typed.Name.Local, \"svg\") {\n\t\t\t\t\treturn \"\", fmt.Errorf(\"root element is not svg\")\n\t\t\t\t}\n\t\t\t\trootSeen = true\n\t\t\t}\n\n\t\t\tif skipDepth > 0 {\n\t\t\t\tskipDepth++\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif _, unsafe := unsafeSVGElements[strings.ToLower(typed.Name.Local)]; unsafe {\n\t\t\t\tskipDepth = 1\n\t\t\t\tcontinue","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/misc.go#L352-L388","documentation":"SanitizeSVG tracks element nesting depth and rejects input once depth exceeds maxSVGDepth (256, kernel/util/misc.go:321). Deep nesting is a classic parser-stack-exhaustion / DoS vector, so the sanitizer caps it. Legitimate SVG icons nest only a handful of levels; exceeding 256 indicates pathological or malicious input.","triggerScenarios":"Calling SanitizeSVG with an SVG whose elements nest more than 256 levels deep — recursively generated SVG, a crafted <g><g><g>... bomb, or deeply nested XML produced by repeated wrapping during transformations.","commonSituations":"Algorithmically generated SVGs (fractals, recursion demos), icons passed through multiple export/import cycles that each wrapped content in extra groups, or malicious uploads targeting XML parser recursion.","solutions":["Flatten the SVG structure (unwrap redundant <g> groups, run an SVG optimizer) before sanitizing","Regenerate the asset from the original source instead of re-exporting repeatedly","Treat the input as malicious if untrusted: reject it rather than raising the limit","If a legitimate deep structure is required, raise maxSVGDepth deliberately with matching stack-safety review"],"exampleFix":"// before\nsvg := strings.Repeat(\"<g>\", 1000) + content + strings.Repeat(\"</g>\", 1000)\nout, err := util.SanitizeSVG(svg) // fails at depth 257\n// after\nsvg := flattenGroups(source) // unwrap nested <g> wrappers\nout, err := util.SanitizeSVG(svg)","handlingStrategy":"validation","validationCode":"if strings.Count(svg, \"<g\")+strings.Count(svg, \"<svg\") > 200 { return errors.New(\"svg nesting too deep\") }","typeGuard":null,"tryCatchPattern":"out, err := util.SanitizeSVG(svg)\nif err != nil && strings.Contains(err.Error(), \"nesting depth exceeds\") {\n    // reject or flatten the SVG before retrying\n}","preventionTips":["Flatten redundant <g> wrappers before import","Avoid repeated export/import cycles that nest content further","Treat deeply nested untrusted SVG as a DoS attempt and reject it"],"tags":["svg","resource-limits","denial-of-service","sanitization"],"backgroundTag":"payload-too-large","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"}