Skip to main content
go-swarm-icons
On this page

SVG Sanitization

Walk through the nine regex stages that strip dangerous content from incoming SVG markup.

Every SVG that enters the library passes through a nine-stage sanitization pipeline. This page documents each stage for readers auditing the library's XSS defenses or evaluating the sanitization scope.

The problem

SVG is an XML-based format that can contain executable content: <script> elements, on* event handlers, javascript: URIs, and external resource references. When SVG icons are loaded from user-provided files, third-party JSON collections, or HTTP APIs, this content must be stripped before rendering to prevent cross-site scripting (XSS) attacks.

When sanitization runs

Sanitization runs automatically inside FromFile and FromString, and on every icon entry parsed from Iconify JSON, which covers the JSON collection, embedded Lucide, and Iconify API providers. Every SVG icon that enters the system through these paths passes through the pipeline. There is no opt-out.

Direct construction via New(content, attrs) does not sanitize. This constructor is intended for content that has already been processed (e.g., output from a provider's cache). For untrusted content, use FromString instead: the sanitizer lives in an internal package and cannot be called on its own.

The 9-stage pipeline

The pipeline applies nine regex replacements in a fixed order. Each stage targets one class of dangerous content. The order matters: earlier stages (like comment stripping) prevent later stages from being bypassed by content hidden inside comments.

Stage Variable Target Example input Result
1 reComment XML comments <!-- <script>x</script> --> Removed entirely
2 reTitle <title> elements <title>My Icon</title> Removed
3 reDesc <desc> elements <desc>Description</desc> Removed
4 reScript <script> elements <script>alert(1)</script> Removed
5 reForeignObject <foreignObject> elements <foreignObject><div>x</div></foreignObject> Removed
6 reOnEvent on* event handlers onclick="evil()" Attribute removed
7 reJSURI javascript: URIs href="javascript:alert(1)" Replaced with href="#"
8 reExternalHref External URLs in <use>/<image> <use href="https://evil.com/x.svg#i"/> href attribute removed
9 reInterTagSpace Inter-tag whitespace > \n < Collapsed to ><

Stage details

Stages 1-5 remove entire elements (opening tag through closing tag), including any nested content. The regexes use (?is) flags for case-insensitive, dot-matches-newline matching, so multiline <script> blocks are handled correctly.

Stage 6 removes on* attributes regardless of where they appear. The regex matches attribute names starting with on followed by any word characters, along with their quoted or unquoted values.

Stage 7 targets href, src, and xlink:href attributes whose values start with javascript:. The attribute value is replaced with "#" rather than removing the attribute entirely, preserving element structure.

Stage 8 removes href and xlink:href attributes from <use> and <image> elements when the URL starts with http:// or https://. This prevents the SVG from loading external resources. Local references (href="#clipPath1") are preserved.

Stage 9 collapses whitespace between tags. This is a formatting cleanup rather than a security measure, reducing the size of the sanitized output.

Regex compilation

All nine regexes are compiled once at package initialization via regexp.MustCompile. There is no per-call compilation cost. The compiled regexes are stored in package-level variables in internal/svgparse/svgparse.go.

What sanitization does not do

The pipeline is regex-based, not a full XML parser. It does not:

  • Validate SVG structure or well-formedness.
  • Parse nested or recursive element patterns beyond what the regexes match.
  • Strip CSS-based attacks inside <style> elements (though <style> elements in SVG icon inner content are uncommon).
  • Remove data URIs in href attributes (only javascript: and https?:// are targeted).

See also

  • Security Model: the six security boundaries that sanitization is part of
  • Icon API reference: the FromFile and FromString constructors that trigger the pipeline
Edit this page

Last updated: