The Woes of Sanitizing SVGs
Full article excerpt tap to expand
The woes of sanitizing SVGs 2026-04-11 on muffin.ink Scratch has a long history of SVG-related vulnerabilities. The source of these is that Scratch parses user-generated (ie. attacker-controlled) content into an <svg> element and appends it into the main document for various operations (eg. measuring SVG bounding box in a more reliable way than viewbox or width/height). No matter how briefly the SVG remains in the main document, this is an inherently unsafe operation. Scratch's approach to making this safe has been to build increasingly complex infrastructure around parsing the SVG and the markup within to remove dangerous parts. I think Scratch's approach to SVG sanitization is doomed. To explain, we have to take a trip through the history of SVG sanitization in Scratch to see how well it has worked so far. 2019: XSS via <script> tag In 2019, a few months after the initial release of Scratch 3, Scratch discovered that SVGs can contain <script> tags that Scratch would cause to be executed when the SVG loads. This is known as an XSS. In Scratch terms, an XSS allows an attacker to take actions on behalf of anyone that loads their project. For example, the attacker can post comments, delete projects, or otherwise try to take over the victim's account. In Scratch Desktop, XSS is elevated to arbitrary code execution because Scratch Desktop enables Electron's dangerous Node.js integration feature. (TurboWarp Desktop has not enabled that feature since v0.2.0 from March 2021) Example from Scratch's test suite: <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> <circle cx="250" cy="250" r="50" fill="red" /> <script type="text/javascript"><![CDATA[ alert('from the svg!') ]]></script> </svg> This was fixed by using a regular expression to remove script tags. Surely, with this change, SVGs are now fully safe and will require no further security fixes. 2020: XSS via oversights in previous fix (CVE-2020-27428) In 2020, apple502j discovered that XSS is still possible. It turns out that the previous fix is utterly defective and can be bypassed by capitalizing <SCRIPT> because the regex is case-sensitive, among several other ways to bypass it. Even if the regex were implemented correctly, it would still not work because there are other ways to embed JavaScript in an SVG. For example, one can use an inline event handler: <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <foreignObject x="1" y="1" width="1" height="1"> <img xmlns="http://www.w3.org/1999/xhtml" src="data:any invalid URL" onerror="alert(1)" /> </foreignObject> </svg> This was fixed by using DOMPurify to remove scripts from the SVG before scratch-svg-renderer appends it into the document. Surely, with this change, SVGs are now fully safe and will require no further security fixes. 2022: HTTP leak via <image> href In 2022, it was discovered that using the href property on an <image> element, an attacker can create an SVG that will invoke an external request when it is loaded. It turns out that while DOMPurify removes executable code, it does not protect against HTTP leaks because "there are too many ways of doing that and our tests showed that it cannot be done reliably". In Scratch terms, an HTTP leak means that a Scratch user can log the IP of anyone that loads their project, possibly revealing information such as location or school…
This excerpt is published under fair use for community discussion. Read the full article at muffin.ink.