Serving User-Generated SVG Safely on Isolated Domains
User-generated Scalable Vector Graphics (SVG) present severe security challenges because they are XML-based files capable of executing JavaScript, triggering cross-site scripting (XSS) attacks, and loading malicious external entities. Serving untrusted SVGs from an isolated domain separates user-uploaded files from your main application’s origin, protecting session tokens, cookies, and sensitive APIs from compromise. This article covers the essential architectural patterns, HTTP headers, sanitization steps, and rendering controls required to host user-uploaded SVGs securely.
Why User-Generated SVGs Are Risky
Unlike raster images (such as JPEG or PNG), SVGs are dynamic documents that support scripting and interactivity. An SVG file can contain:
<script>tags that execute arbitrary JavaScript when the file is viewed directly in a browser.- Inline event handlers (such as
onloadoronerror) embedded in standard SVG shapes. <a>links withjavascript:URIs.- External resource references (via
<image>,<use>, or XML external entities) that can lead to Server-Side Request Forgery (SSRF) or XML External Entity (XXE) vulnerabilities during server-side processing.
Best Practices for Domain Isolation
1. Use a Separate, Cookie-Free Origin
Host all user-uploaded content on a completely distinct apex domain or a non-shared subdomain that does not share cookies with your primary domain.
- Preferred: Use a completely different domain (e.g.,
example-usercontent.cominstead ofexample.com). This ensures total isolation fromlocalStorage,sessionStorage, and parent-domain session cookies. - Alternative: If using a subdomain (e.g.,
uploads.example.com), ensure your authentication cookies onexample.comare scoped strictly without theDomain=.example.comattribute.
2. Configure Strict Content Security Policy (CSP)
When serving the SVG from the isolated domain, enforce a restrictive CSP header to prevent any script execution in the event a user opens the SVG link directly.
Content-Security-Policy: default-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; sandbox
The sandbox directive disables script execution, form
submissions, and popups within the SVG context.
3. Set Crucial HTTP Security Headers
Accompany every SVG response with security headers to enforce the correct content type and prevent MIME-sniffing:
Content-Type: image/svg+xml; charset=utf-8: Explicitly defines the MIME type.X-Content-Type-Options: nosniff: Prevents browsers from attempting to execute the payload as HTML if content sniffing occurs.Cross-Origin-Resource-Policy: same-site(orcross-origindepending on embed needs): Controls which origins can read the file.Access-Control-Allow-Origin: Explicitly restrict which domains can fetch the SVG viafetch()orXMLHttpRequest.
File Processing and Sanitization
Server-Side Sanitization
Never store or serve raw user-submitted SVG files without cleaning them first:
- Parse with a Hardened XML Parser: Disable DTD parsing, external entity resolution (XXE prevention), and XInclude processing.
- Strip Executable Nodes: Remove all
<script>,<foreignObject>,<iframe>, and<object>elements. - Sanitize Attributes: Strip all event handlers
(
onload,onclick,onerror, etc.) and ensurehreforxlink:hrefattributes only use safe protocols (http,https, or relative paths), explicitly blockingjavascript:ordata:URIs. - Use Dedicated Libraries: Use battle-tested tools such as DOMPurify (configured specifically for SVG/XML) or SVG-specific sanitizers in your backend language.
Optional Raster Conversion
If full vector scalability is not strictly required by your application (for example, profile pictures or document previews), convert uploaded SVGs into static raster formats like WebP or PNG on upload. This eliminates the vector attack surface entirely.
Safe Rendering in the Client Application
How your main application displays the SVG matters just as much as where it is hosted:
- Safe:
<img>tags or CSSbackground-image: When loaded via<img src="https://isolated-domain.com/file.svg">, modern browsers automatically disable JavaScript execution, external network requests, and DOM interaction inside the SVG. - Dangerous: Inline
<svg>: Never inject user-generated SVG markup directly into your main document’s DOM usinginnerHTMLor framework-equivalent methods, as scripts will execute directly in the context of your main origin. - Dangerous:
<iframe>,<object>, or<embed>: These elements render the SVG as an independent document context and can run embedded scripts if the CSP on the hosting domain is misconfigured.