XSS Attacks via SVG Files Disguised as GIFs
This article explains how attackers leverage Scalable Vector Graphics
(SVG) disguised with a .gif extension to execute Cross-Site
Scripting (XSS) attacks. It covers how file validation mechanisms are
bypassed, how web servers and browsers handle ambiguous MIME types, and
the technical mechanics that allow embedded JavaScript to execute within
the victim's session context.
Unlike traditional raster formats such as GIF, JPEG, or PNG, an SVG
is an XML-based vector image format. Because it is written in XML, the
SVG specification natively supports the inclusion of script elements,
such as <script> tags, and inline event handlers,
such as onload or onerror. When an SVG
document is rendered directly by a web browser, the browser's XML parser
interprets the markup and executes any embedded JavaScript within the
origin of the hosting domain.
To exploit file upload mechanisms that permit images but ban
dangerous formats, attackers rename an SVG file to use a
.gif extension (e.g., exploit.gif). If an
application solely validates uploads using the file extension, the file
is accepted and stored on the server. In more advanced scenarios where
the application verifies magic bytes, attackers create a GIF/SVG
polyglot file. This file begins with valid GIF header signatures, such
as GIF89a, immediately followed by valid SVG XML markup
containing executable script payloads.
The execution of the XSS payload relies on how the file is served and
interpreted by the browser. If the web server does not explicitly send
an accurate Content-Type: image/gif header, modern browsers
perform MIME-type sniffing to deduce the file format. Upon scanning the
file and encountering XML and SVG elements, the browser identifies the
resource as image/svg+xml. When a user navigates directly
to the file URL or the file is rendered in an inline context such as an
<iframe> or an <object> tag, the
browser treats the file as an active document, thereby executing the
embedded JavaScript.
Execution also occurs when misconfigured servers rely on
client-provided metadata or fail to enforce strict content handling. If
the server serves the disguised file with a generic MIME type like
text/plain or application/octet-stream without
the X-Content-Type-Options: nosniff HTTP header, browsers
attempt to determine the content type automatically. Once the browser
detects markup, the payload triggers standard stored XSS behavior,
enabling attackers to steal session cookies, manipulate the DOM, or
perform unauthorized actions on behalf of the victim.
Preventing this vulnerability requires robust file upload and delivery controls:
- Server-Side Re-encoding: Process all uploaded images through an image processing library (such as ImageMagick or Sharp) to re-encode them into strict raster formats, which strips out any XML markup or scripts.
- Strict Header Enforcement: Explicitly set the
Content-Typeheader based on server-side content verification and always includeX-Content-Type-Options: nosniffin HTTP responses. - Isolated Storage Domains: Serve all user-generated content from an isolated, sandboxed domain or content delivery network (CDN) that does not share authentication cookies or session states with the main application.
- Content Security Policy (CSP): Implement a strict Content Security Policy that restricts script execution and disallows inline scripts.