The woes of sanitizing SVGs

Scratch's long history of SVG vulnerabilities highlights the inherent dangers of parsing user-generated content, evolving from simple XSS attacks to complex HTTP leaks via CSS.
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. This was fixed by using a regular expression to remove script tags. ## 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. This was fixed by using DOMPurify to remove scripts from the SVG. ## 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. 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. This was fixed by adding DOMPurify hooks to remove href properties from all elements if the URL refers to a remote website. ## 2023: HTTP leak via CSS @import In 2023, it was discovered that using a CSS @import statement inside of a <style> element, an attacker could create a project that invokes external requests. This was fixed by integrating a CSS parser written in JavaScript to remove dangerous parts of the CSS. ## 2024: XSS via Paper.js In 2024, an XSS was discovered in Paper.js, a library Scratch uses in the costume editor. It turns out that while Scratch sanitized SVGs before working on them in scratch-svg-renderer, unsanitized SVGs were still being passed to Paper.js. This was fixed by extending the existing SVG sanitization code to run when loading an SVG. ## 2025: HTTP leak via CSS url() In 2025, it was discovered that using url() inside of certain CSS rules, an attacker can create an SVG that will invoke an external request. This was fixed by substantially expanding the SVG sanitization code to also search for any usage of url(). ## 2026: HTTP leak via several bugs in the previous code In 2026, it was discovered that using url() inside of certain CSS rules, it is still possible for an attacker to create an SVG that will invoke an external request. It turns out there were at least three unique bugs: CSS escape codes, multiple url() calls in one attribute, and CSS variables.
Source: Hacker News















