CVE-2026-41239
Medium · 6.8CVSS
6.8
EPSS
0.4%
Published
Apr 23, 2026
CISA due date
—
Cloudanix analysis
Some websites may still run malicious code hidden in user-submitted content even though they appear to sanitize it first.
- Exploitation
- Requires User Interaction
- Attacker needs
- None
- Complexity
- High
- Impact
- Data Exposure
- Component
- Library
- Class
- XSS
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Medium
What it actually does
DOMPurify versions from 1.0.10 before 3.4.0 can fail to remove template expressions such as {{...}} when SAFE_FOR_TEMPLATES is used together with RETURN_DOM or RETURN_DOM_FRAGMENT. In string-return mode, DOMPurify strips these template markers as intended; in DOM-return modes, the sanitized DOM can still contain expressions that are later interpreted by client-side template frameworks, particularly Vue 2. If attacker-controlled HTML is sanitized with this vulnerable configuration and then mounted or compiled by a framework that evaluates template syntax, the attacker can execute JavaScript in the victim’s browser. The impact is reflected client-side code execution in the application’s origin, enabling theft of page-accessible secrets, session actions as the user, and manipulation of page content.
Why it matters to the business
Applications that rely on DOMPurify to safely display user-supplied HTML may still expose users to cross-site scripting if they combine SAFE_FOR_TEMPLATES with DOM-return modes and a template-evaluating frontend framework. Successful exploitation can lead to account takeover, unauthorized actions performed as legitimate users, data exposure from the browser session, fraudulent content injection, and loss of trust in affected web applications. The CVSS score is moderate at 6.8 and EPSS is low and stable at 0.00248, with no known KEV listing or known ransomware use, so broad internet exploitation is not currently indicated; however, affected applications with rich user-generated content or Vue 2-style template compilation should treat this as a priority application-security fix.
How an attack unfolds
An attacker first identifies a feature that accepts and later renders user-controlled HTML, such as comments, profile fields, messages, CMS content, support tickets, or document previews. The target application sanitizes this content with DOMPurify using SAFE_FOR_TEMPLATES, but requests a DOM node or DOM fragment using RETURN_DOM or RETURN_DOM_FRAGMENT instead of a sanitized string. The attacker submits HTML containing template delimiters that are expected to be removed, for example Vue-style {{...}} expressions. Because the vulnerable DOM-return path does not strip those expressions, the sanitized output still contains framework-interpretable template syntax. When the application inserts the returned DOM into a page and a framework such as Vue 2 compiles or evaluates that portion of the DOM, the attacker-controlled expression can execute in the page context. The resulting script can read page-accessible data, perform actions using the victim’s authenticated session, alter displayed content, or exfiltrate sensitive values available to JavaScript.
How to fix it
Upgrade DOMPurify to version 3.4.0 or later wherever the library is used, including direct dependencies, bundled frontend assets, vendored JavaScript, and transitive package-lock or yarn-lock references. If immediate upgrade is not possible, avoid using SAFE_FOR_TEMPLATES together with RETURN_DOM or RETURN_DOM_FRAGMENT on untrusted input; prefer string-return sanitization followed by safe insertion methods, or ensure that sanitized output is never passed into a framework compiler or template-evaluating path. Disable runtime template compilation for untrusted DOM regions where possible, and avoid Vue 2-style compilation of attacker-influenced HTML. Apply defense-in-depth controls such as a restrictive Content Security Policy that avoids unsafe-inline, separates untrusted content into sandboxed iframes where feasible, and prevents sensitive tokens from being accessible to JavaScript. Rebuild and redeploy frontend bundles after dependency updates, because updating the package alone may not affect already-built static assets.
How to confirm the fix worked
Confirm that every deployed application bundle and package manifest using DOMPurify resolves to version 3.4.0 or later. Search source code for DOMPurify.sanitize calls that combine SAFE_FOR_TEMPLATES with RETURN_DOM or RETURN_DOM_FRAGMENT, and verify those code paths have been removed, upgraded, or isolated from template compilation. Inspect built JavaScript bundles to ensure they contain the patched DOMPurify version, not only the development dependency tree. Add regression tests that sanitize input containing {{...}} template expressions with the same configuration used in production and confirm the resulting rendered output does not execute or evaluate as a template. In browser testing, submit benign canary template expressions through representative rich-text fields and verify they are stripped, escaped, or rendered inert after sanitization and framework rendering.
Typical attack path
- Find an application feature that stores or reflects user-supplied HTML and renders it to other users.
- Determine or infer that the application uses DOMPurify with SAFE_FOR_TEMPLATES and a DOM-return mode such as RETURN_DOM or RETURN_DOM_FRAGMENT.
- Craft HTML containing template expressions that survive DOMPurify’s vulnerable sanitization path.
- Submit the payload through the affected input channel, such as a comment, profile field, message, rich-text editor, or CMS component.
- Wait for the content to be rendered in a page where a template-evaluating framework, especially Vue 2, compiles or processes the DOM.
- Execute JavaScript in the victim’s browser under the vulnerable application’s origin.
- Use the browser context to steal accessible data, perform authenticated actions, or inject misleading content.
How to detect it
To assess prior exploitation, review web application logs, WAF logs, CDN request logs, API gateway logs, and application audit trails for user-submitted content containing template delimiters such as {{ and }} in fields that later render as HTML. Focus on rich-text editors, comments, profile fields, CMS pages, support tickets, messages, document previews, and any endpoint that stores or reflects HTML. Search historical stored content for Vue-style template expressions, JavaScript constructor chains, fetch/XMLHttpRequest calls, image beacons, script-like strings inside {{...}}, and payloads submitted shortly before unusual user actions. Browser-side exploitation may leave limited server evidence, so correlate suspicious content submissions with anomalous account activity, unexpected profile or content modifications, reports of pop-ups or redirects, CSP violation reports, and outbound requests to unfamiliar domains triggered from affected pages. Also review dependency and source history to identify whether vulnerable DOMPurify versions and the risky SAFE_FOR_TEMPLATES plus RETURN_DOM or RETURN_DOM_FRAGMENT configuration were present during the period under investigation. There are no universal file, process, registry, or network indicators for this library flaw; detections should be based on suspicious payload patterns and application-specific content storage locations.
- {{constructor.constructor
- {{this.constructor.constructor
- {{[].filter.constructor
- {{''.sub.constructor
- {{ $root.constructor.constructor
- {{_c.constructor.constructor
- {{alert(
- {{prompt(
- {{confirm(
- {{fetch(
- {{XMLHttpRequest
- {{document.cookie
- {{localStorage
- {{sessionStorage
- {{new Image
- {{location.href
- {{location='
- {{eval(
- {{Function(
What your security team should do
- Inventory applications and frontend bundles that include DOMPurify versions 1.0.10 through 3.3.x, including vendored and transitive copies.
- Prioritize applications that process user-generated HTML and use Vue 2 or any client-side framework that compiles template syntax from DOM content.
- Upgrade DOMPurify to 3.4.0 or later and rebuild/redeploy all affected frontend assets.
- Search code for the risky configuration combination: SAFE_FOR_TEMPLATES with RETURN_DOM or RETURN_DOM_FRAGMENT.
- Review recent submissions to rich-text, profile, messaging, CMS, and comment features for suspicious template expressions.
- Deploy or tune CSP to reduce the impact of successful client-side script execution.
- Add automated dependency checks and application tests covering sanitizer behavior for template expressions.
- Because EPSS is low, no KEV listing exists, and no mature public exploit is indicated, sequence remediation based on exposure and user-generated-content risk rather than emergency internet-wide exploitation assumptions.
The record
DOMPurify is a DOM-only cross-site scripting sanitizer for HTML, MathML, and SVG. Starting in version 1.0.10 and prior to version 3.4.0, `SAFE_FOR_TEMPLATES` strips `{{...}}` expressions from untrusted HTML. This works in string mode but not with `RETURN_DOM` or `RETURN_DOM_FRAGMENT`, allowing XSS via template-evaluating frameworks like Vue 2. Version 3.4.0 patches the issue.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| npm | dompurify | 1.0.10 | 3.4.0 |
Related vulnerabilities
- GHSA-crv5-9vww-q3g8 DOMPurify has a SAFE_FOR_TEMPLATES bypass in RETURN_DOM mode Same vulnerability
- GHSA-cmwh-pvxp-8882 DOMPurify: Permanent `ALLOWED_ATTR` pollution via `setConfig()` bypassing the hook… Also affects dompurify
- GHSA-vxr8-fq34-vvx9 DOMPurify: Trusted Types policy survives `clearConfig()` and can poison later… Also affects dompurify
- GHSA-gvmj-g25r-r7wr DOMPurify: SAFE_FOR_TEMPLATES bypass - template expressions survive sanitization inside… Also affects dompurify
- GHSA-rp9w-3fw7-7cwq DOMPurify IN_PLACE Sanitization Bypass via Attached Shadow Root Inside .content Also affects dompurify
- GHSA-x4vx-rjvf-j5p4 DOMPurify: `IN_PLACE` mode trusts attacker-controlled `nodeName` on live non-form nodes… Also affects dompurify
- GHSA-76mc-f452-cxcm DOMPurify: Hook mutation of `data.allowedTags` / `data.allowedAttributes` permanently… Also affects dompurify
- GHSA-hpcv-96wg-7vj8 DOMPurify: Cross-realm IN_PLACE sanitization leaves executable markup intact via… Also affects dompurify