Stored XSS via SVG File Upload

LS
3 min readSep 27, 2023

--

This report will be exploring a vulnerability I found by uploading a malicious SVG file containing an XSS payload.

A Scalable Vector Graphic (SVG) is a unique type of image format. Unlike other varieties, SVGs don’t rely on unique pixels to make up the images you see. Instead, they use ‘vector’ data. SVG files are written in XML, a markup language used for storing and transferring digital information. What some people don’t know is that SVG files are capable of holding javascript using regular <script> tags or <[CDATA[ … ]]> blocks and browsers will parse and execute the code when the file URL is requested directly, examples below:

<?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 version="1.1" baseProfile="full" >
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert(document.domain);
</script>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
<script>//<![CDATA[
alert(document.domain)
//]]>
</script>
</svg>

The Testing

I was exploring functionality on a digital marketplace app and started poking around profile picture upload functionalities. This app contained regular user profiles as well as digital store profiles which both the option of having a profile picture. The user profile picture was hosted on a third party domain so I didn’t look into it too much but the digital store profile picture was hosted on a assets.target.com domain, where target.com was the site I was testing.

I tried uploading a file that contained code similar to the one shown above and I immediately got an error saying that only JPG or PNG files were allowed, my file obviously had a .svg extension

The Bypass

While I was doing this I was inspecting the traffic on Burp Suite and I immediately noticed that that this blocking action on my malicious SVG file did not generate any network traffic that was being sent server side. What this meant was that this file type validation was done entirely on the client side without reaching the app’s servers. I couldn’t find where exactly this check was done because the frontend JS code was heavily minified however I started just started to mess with it anyway. So the first obvious thing was just adding the .png extension to the already existing .svg extension so the file name read something like “payload.svg.png” and what do you know, file was uploaded. That’s it, that’s the bypass.

all right then

There must’ve been some string or regex check that just made sure the file ended with .png or .jpg and not the content of the actual file. After the file was uploaded I tried opening the file using the direct URL of where it was hosted and the Javascript alert popped.

The Impact

Unfortunately the impact here was not a big one for multiple reasons. The first one being that I hadn’t noticed that this assets.target.com domain didn’t really contain any sensitive cookies or data so there was nothing to steal.

The second big mitigating factor was that after the file was processed there were some additional parameters added to the file URL to resize the picture before it was added to the store’s frontend which meant it didn’t immediately pop. An attacker would have to send the URL directly to a victim to execute any javascript, as opposed to the javascript running immediately when anyone visiting the store. The code was also getting blocked by CORS from accessing other subdomains of the same site.

The only attack vector I could see here is creating an iframe that would display a fake login page or other phishing mechanisms but as far as actually exploiting the site’s functionality in another user’s context it was not possible.

--

--