Securing Untrusted SVGs with Content-Disposition Attachment

Serving untrusted SVG files poses significant security risks because Scalable Vector Graphics can contain executable JavaScript and other active content. The primary function of the Content-Disposition: attachment HTTP response header is to instruct the browser to download the file directly to the user’s local disk rather than rendering it inline within the browser window. By forcing a download, the header prevents the browser from executing malicious scripts embedded within the SVG in the context of your domain, effectively neutralizing stored Cross-Site Scripting (XSS) attacks.

The Security Risk of Untrusted SVGs

Unlike raster image formats like JPEG or PNG, SVG is an XML-based vector image format. Because it follows standard XML and HTML capabilities, the SVG specification supports embedded <script> tags, event handlers (such as onload or onerror), and external resource loading.

When a user uploads an untrusted SVG file and your server serves it directly with an image/svg+xml MIME type, a browser rendering the file inline treats it like a web document. If an attacker embeds malicious JavaScript, the script executes within the origin domain, giving the attacker access to session tokens, cookies, and authenticated actions on behalf of the victim.

How Content-Disposition: attachment Mitigates the Risk

The Content-Disposition header controls the presentation of the requested resource. It typically uses one of two values:

When you configure the response header as Content-Disposition: attachment (or Content-Disposition: attachment; filename="image.svg"), the browser will not parse or execute the internal XML structure in the context of the hosting website. Because the file is not rendered as an active document in a tab or frame, embedded scripts cannot run against the user’s current session or access domain resources.

Best Practices When Serving Untrusted SVGs

While Content-Disposition: attachment provides a strong defense against inline XSS, securing untrusted media requires a layered approach:

  1. Enforce the Header Globally for User Content: Ensure all user-uploaded SVG assets strictly include Content-Disposition: attachment; filename="safe-name.svg".
  2. Set Proper Content-Type: Always pair the header with the accurate Content-Type: image/svg+xml header to prevent MIME-sniffing vulnerabilities, alongside X-Content-Type-Options: nosniff.
  3. Sanitize on Upload: If SVGs must be rendered inline on your platform, use an XML sanitizer to strip all <script>, <iframe>, <foreignObject>, and inline event handlers before saving the file.
  4. Use an Isolated Domain: Serve user-uploaded content from a completely separate, sandboxed domain or CDN (e.g., usercontent.example.com rather than app.example.com) without shared cookies or sensitive access.
  5. Implement a Restrictive CSP: If inline display is necessary, serve the file with a dedicated Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline' header to block script execution at the browser level.