Stored XSS via SVG Upload


Engagement Summary
During a recent web application penetration test, I discovered a Stored Cross-Site Scripting (XSS) vulnerability by uploading a malicious SVG file containing inline JavaScript.
This blog outlines how the vulnerability was discovered, exploited, and responsibly disclosed.
What Is Stored XSS?
Stored XSS occurs when user-supplied input is stored by the server (e.g., in a database or file) and later rendered in a way that executes code in other users’ browsers. In this case, the payload was stored as an SVG file and served back to users with insufficient sanitization or CSP.
Vulnerable Functionality
The application allowed users to upload image files, including SVGs. These images were later rendered directly into the DOM using an <img>
tag.
Example HTML:
htmlCopyEdit<img src="/uploads/user-image.svg">
Here’s the catch: the server preserved the Content-Type
header of the uploaded file (e.g., image/svg+xml
), and served the file inline without sanitization or restrictive CSP headers.
The Malicious SVG Payload
I crafted a minimal SVG file with embedded JavaScript:
xmlCopyEdit<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" onload="alert(document.domain)">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
</svg>
The
onload
event on the<svg>
element triggers when the image is rendered.The payload triggers a simple
alert()
— in a real scenario, this could be replaced with data exfiltration.
Proof of Concept
Upload the malicious
.svg
file through the image upload feature.Note the image is embedded using
<img src="/uploads/user.svg">
.When any user visits the page containing the uploaded image, the
onload
JavaScript runs in their browser.
📸 Result: JavaScript executes in the victim’s browser — a stored XSS.
Why This Works
SVG is not sanitized.
SVG allows inline JavaScript and event handlers.
Uploaded file was served with
Content-Type: image/svg+xml
.No Content Security Policy (CSP) to restrict inline scripts.
Rendering the SVG in an
<img>
tag does not prevent JavaScript execution in SVGs.
Note: Despite common belief,
<img src="malicious.svg">
can execute JS in some SVGs, especially in legacy or improperly configured browsers.
Takeaway
Even "image" files like SVGs can carry dangerous payloads. Always assume that uploaded files are hostile and sanitize or sandbox them appropriately.
There were constraints which stopped me to perform further attacks
You can do it yourself, or we can do it for you. You handle everything, we handle pentesting for you. Contact us today to get free consultation.
Subscribe to my newsletter
Read articles from RockByte Security directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
