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:
inline: The default behavior, which attempts to display the content directly in the browser.attachment: Directs the browser not to display the content directly, but to save it as a local file or trigger a “Save As” download prompt.
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:
- Enforce the Header Globally for User Content:
Ensure all user-uploaded SVG assets strictly include
Content-Disposition: attachment; filename="safe-name.svg". - Set Proper Content-Type: Always pair the header
with the accurate
Content-Type: image/svg+xmlheader to prevent MIME-sniffing vulnerabilities, alongsideX-Content-Type-Options: nosniff. - 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. - Use an Isolated Domain: Serve user-uploaded content
from a completely separate, sandboxed domain or CDN (e.g.,
usercontent.example.comrather thanapp.example.com) without shared cookies or sensitive access. - 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.