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

Security Model

Review the six threat boundaries the library defends against and how each is mitigated.

The library processes SVG content from potentially untrusted sources: user-uploaded files, third-party JSON collections, and remote HTTP APIs. This page documents the six security boundaries, their threat models, and the specific mitigations.

Overview

Six security boundaries protect against the most common attack vectors.

1. Directory path traversal

Threat: a crafted icon name like ../../etc/passwd could read files outside the icon directory.

Mitigation: DirectoryProvider resolves the candidate file path with filepath.EvalSymlinks (which follows symlinks to their real location), then checks that the resolved path starts with the provider's root directory path plus the OS path separator. If the resolved path escapes the root, Get and Has return false.

Request: Get("../../etc/passwd")
1. Join root + name: /icons/../../etc/passwd
2. EvalSymlinks: /etc/passwd
3. Prefix check: /etc/passwd does not start with /icons/
4. Result: false (blocked)

Symlink attacks are also blocked. A symlink inside the icon directory that points outside it is resolved by EvalSymlinks, and the prefix check catches the escape.

2. SVG XSS

Threat: SVG files can contain <script> elements, on* event handlers, javascript: URIs, <foreignObject> with arbitrary HTML, and external resource references.

Mitigation: the library applies a 9-stage regex pipeline to all SVG inner content. This pipeline runs automatically inside FromFile, FromString, and the Iconify JSON parsing path. There is no way to bypass sanitization through the standard constructors.

The pipeline strips:

  • <script>, <foreignObject>, <title>, <desc> elements (entire element including content).
  • on* event handler attributes.
  • javascript: URIs (replaced with href="#").
  • External https?:// URLs in <use> and <image> href attributes.
  • XML comments (which could hide malicious content from naive scanners).

3. Attribute name XSS

Threat: a crafted attribute name could break out of the SVG element. For example, an attribute named onclick or " onload="evil() could inject event handlers.

Mitigation: Icon.renderAttributes() (called by ToHTML) validates every attribute name against the regex:

^[a-zA-Z_:][\w:.\-]*$

Names that do not match are silently dropped from the output. This allows standard SVG attributes (viewBox, stroke-width, xmlns:xlink) while rejecting names containing spaces, quotes, or other characters that could break the attribute syntax.

4. Attribute value XSS

Threat: an attribute value like " onload="evil() could inject event handlers if rendered without escaping.

Mitigation: all attribute values are escaped with html.EscapeString() before being written into the <svg> element by ToHTML. This converts <, >, &, ", and ' to their HTML entity equivalents.

Go
// Input: data-x="<>&\"'"
// Output: data-x="&lt;&gt;&amp;&#34;&#39;"

The escaping is unconditional and applied to every attribute value, including those from trusted sources.

5. Iconify SSRF

Threat: the IconifyProvider makes HTTP requests. If an attacker can control the host list, the provider could be used as a server-side request forgery (SSRF) vector to probe internal networks.

Mitigation: the provider only contacts hosts in its configured host list. The default list contains three known Iconify API servers:

  1. https://api.iconify.design
  2. https://api.simplesvg.com
  3. https://api.unisvg.com

The WithHosts option allows overriding this list, but the caller must provide the replacement list explicitly. There is no mechanism for user input to influence the host list at runtime unless the application code exposes it.

The HTTP request URL is constructed from the configured host, the provider's prefix (set at construction time), and the icon name (URL-escaped via url.PathEscape and url.QueryEscape). The response body is limited to 1 MB via io.LimitReader.

Limitation: this is not a hard allowlist in the sense that WithHosts can be called with arbitrary URLs. The protection relies on the application developer not exposing WithHosts to untrusted input. The default configuration is safe.

6. JSON alias loops

Threat: an Iconify JSON collection could contain a circular alias chain (a -> b -> c -> a), causing infinite recursion during icon resolution.

Mitigation: JsonCollectionProvider.resolveAlias tracks recursion depth and stops at 10. If the depth limit is reached, the alias resolution returns nil, and Get returns (nil, false).

JSON
{
"aliases": {
"a": {"parent": "b"},
"b": {"parent": "c"},
"c": {"parent": "a"}
}
}

Requesting icon "a" follows the chain a -> b -> c -> a and hits the depth limit at step 4. The icon is treated as not found rather than causing a stack overflow.

The depth limit of 10 is sufficient for legitimate alias chains (which rarely exceed 2-3 levels) while preventing pathological cases.

See also

Summary

Boundary Threat Mitigation Location
Directory paths Path traversal filepath.EvalSymlinks + prefix check directory_provider.go
SVG content XSS via scripts/handlers/URIs 9-stage sanitization pipeline internal/svgparse/svgparse.go
Attribute names XSS via crafted keys Regex validation, invalid names dropped icon.go
Attribute values XSS via injection html.EscapeString() on all values icon.go
Iconify URLs SSRF Configured host list (defaults to 3 Iconify hosts) iconify_provider.go
JSON aliases Infinite recursion Depth limit of 10 json_provider.go
Edit this page

Last updated: