Technical

SVG Security Best Practices: How to Prevent XSS in SVG File Uploads

SVG Genie TeamSVG Design Expert & Technical Writer at SVG Genie
||10 min read

Reviewed by SVG Genie Editorial Team

Most developers treat SVGs like images (PNGs or JPGs). But SVG is XML code. It's a document format that supports scripting, external resources, and event handlers.

This makes SVG a powerful attack vector. A malicious user can upload an SVG that executes JavaScript in your users' browsers, steals cookies, or performs CSRF attacks.

If you allow users to upload SVGs, or if you render SVGs from untrusted sources, this guide is mandatory reading.

The Threat: Stored XSS

The most common attack is Stored Cross-Site Scripting (XSS). An attacker embeds a script in an SVG:

<svg xmlns="http://www.w3.org/2000/svg">
  <script>alert('XSS')</script>
</svg>

Or uses event handlers:

<svg xmlns="http://www.w3.org/2000/svg" onload="alert('XSS')">
  <rect x="0" y="0" width="100" height="100" />
</svg>

When another user views this "image," the script executes in their session.

How to Defend Your App

1. Serve as an Image (<img>)

The safest way to render untrusted SVG is using the <img> tag.

<!-- Safe -->
<img src="user-upload.svg" alt="User content" />

Browsers automatically disable scripts and external resource loading for SVGs loaded inside <img> tags. The script is technically still there, but it won't run.

However, this blocks animations and interactivity.

2. Sanitization (The Gold Standard)

If you must inline the SVG (e.g., <svg>...</svg> in your HTML) or allow users to download it, you must sanitize it.

Sanitization involves parsing the XML and stripping out dangerous tags (<script>, <foreignObject>) and attributes (onload, onclick, javascript: links).

Recommended Tool: DOMPurify

For frontend sanitization:

import DOMPurify from 'dompurify';

const dirtySVG = '<svg onload="alert(1)">...</svg>';
const cleanSVG = DOMPurify.sanitize(dirtySVG, {
  USE_PROFILES: { svg: true, svgFilters: true }
});

// Now safe to inject
document.getElementById('container').innerHTML = cleanSVG;

Backend Sanitization:

Never trust client-side sanitization alone. Use a library like bleach (Python) or sanitize-html (Node.js) configured specifically for SVG allowlists.

3. Content Security Policy (CSP)

CSP is your safety net. If a script slips through, CSP prevents it from executing.

Content-Security-Policy: default-src 'self'; img-src 'self' data:; script-src 'self';

If your CSP forbids inline scripts (script-src 'self'), an SVG with <script>alert(1)</script> will be blocked by the browser even if you display it directly.

4. Content-Disposition Header

If you host user SVGs for download or direct viewing (e.g., yoursite.com/uploads/file.svg), ensure the server sends the correct headers so the browser doesn't execute it.

Content-Type: image/svg+xml
Content-Security-Policy: script-src 'none'; object-src 'none';
Content-Disposition: attachment; filename="download.svg"

Forcing Content-Disposition: attachment ensures the file is downloaded rather than rendered in the browser window, neutralizing XSS risks.

Dangerous Features to Watch For

When configuring a custom sanitizer, block these elements and attributes:

Elements:

  • <script>
  • <foreignObject> (can contain HTML/JS)
  • <iframe (if valid in context)
  • <use> (can reference external malicious resources)

Attributes:

  • onload, onclick, onmouseover, etc.
  • xlink:href pointing to javascript: URLs
  • href pointing to javascript: URLs

The "Billions Laughs" Attack (XML Bomb)

SVG is XML, so it's vulnerable to XML Entity Expansion attacks.

<!DOCTYPE svg [
 <!ENTITY lol "lol">
 <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 ...
]>
<svg>&lol9;</svg>

This recurses exponentially, consuming server RAM and causing Denial of Service (DoS).

Fix: Disable DTD processing (DOCTYPE) in your XML parser on the backend. Most modern XML parsers disable this by default, but verify your configuration.

Summary Checklist

  1. Prefer <img> tags for untrusted content.
  2. Sanitize on the server before saving/serving.
  3. Sanitize on the client (DOMPurify) before inlining.
  4. Use strict CSP headers.
  5. Disable XML DTDs to prevent DoS.

SVG is fantastic, but it's a document, not just a picture. Treat it with the same caution you'd give to an HTML file.


Related Articles:

Create your own SVG graphics with AI

Describe what you need, get a production-ready vector in seconds. No design skills required.

Try SVG Genie Freearrow_forward

About This Article

This article was written by SVG Genie Team based on hands-on testing with SVG Genie's tools and years of experience in vector design and web graphics. All recommendations reflect real-world usage and are reviewed by the SVG Genie editorial team for accuracy.

About the Author

SVG Genie Team

SVG Design Expert & Technical Writer at SVG Genie

SVG Genie Team is a vector design specialist and technical writer at SVG Genie with years of hands-on experience in SVG tooling, AI-assisted design workflows, and web graphics optimization. Their work focuses on making professional vector design accessible to everyone.

More articles by SVG Genie Teamarrow_forward

Ready to Create Your Own Vectors?

Start designing with AI-powered precision today.

Get Started Freearrow_forward