CVE-2026-49458
JavaScript vulnerability analysis and mitigation

Overview

CVE-2026-49458 is a cross-site scripting (XSS) sanitizer bypass vulnerability in DOMPurify, a widely used DOM-only XSS sanitizer for HTML, MathML, and SVG. The flaw affects all versions of DOMPurify up to and including 3.4.5 (npm package dompurify), and was first published by cure53 on May 26, 2026, with the GitHub Advisory Database entry updated on June 15, 2026. The vulnerability arises specifically when DOMPurify.sanitize(node, { IN_PLACE: true }) is called with a same-origin foreign-realm DOM node (e.g., from an iframe), causing critical sanitization branches to be silently skipped. It carries a CVSS v3.1 base score of 6.1 (Medium) (Github Advisory, DOMPurify Advisory).

Technical details

The root cause is a trust boundary violation (CWE-501) and protection mechanism failure (CWE-693) leading to XSS (CWE-79): JavaScript instanceof checks are per-realm, meaning that constructors from the parent realm (e.g., HTMLFormElement, NamedNodeMap, DocumentFragment) do not match objects created in a foreign realm such as an iframe's document. DOMPurify's entry point (_isNode) accepts foreign-realm nodes using a realm-agnostic shape check, but three critical internal security functions — _isClobbered (checks element instanceof HTMLFormElement), _sanitizeShadowDOM (checks content instanceof DocumentFragment), and _sanitizeAttachedShadowRoots (checks sr instanceof DocumentFragment) — all use parent-realm constructors and silently fail-open for foreign-realm objects. This causes DOMPurify to skip DOM clobbering detection, template-content recursion, and shadow-DOM sanitization, allowing attacker-controlled markup (event handlers, onerror attributes, shadow root content) to survive sanitization intact. The vulnerability is only exploitable via the IN_PLACE: true option with a node constructed in a different same-origin realm; string-input sanitization and same-realm IN_PLACE calls are not affected (DOMPurify Advisory).

Impact

Successful exploitation allows an unauthenticated attacker to inject executable JavaScript markup that survives DOMPurify sanitization, resulting in XSS execution in the context of the victim's browser session. Attacker-controlled payloads can persist in form root attributes (e.g., onmouseover, onclick, action=javascript:), <template> element content, and attached shadow roots — all of which activate when the consuming application inserts or activates the sanitized node. Downstream consequences include session cookie theft, credential harvesting, forged requests, and arbitrary JavaScript execution scoped to the affected origin. Indirect impact extends to DOM-based template engines (Lit, Polymer, Vue, FAST), WYSIWYG editors rendering preview content in iframes, and email/HTML preview libraries that parse content in isolated iframes before sanitizing with a parent-realm DOMPurify instance (DOMPurify Advisory, Github Advisory).

Exploitation steps

  1. Identify a vulnerable target: Locate a web application that uses DOMPurify ≤ 3.4.5 with the IN_PLACE: true option and processes DOM nodes constructed in a same-origin iframe or other foreign realm (e.g., WYSIWYG editors, email preview tools, template engines using iframe sandboxing).
  2. Craft a malicious same-origin iframe: Create a same-origin iframe (e.g., via document.createElement('iframe') with srcdoc) whose document will be used to construct attacker-controlled DOM nodes in a foreign realm.
  3. Construct the malicious payload node: Inside the iframe's contentDocument, create a DOM node containing the XSS payload. For form clobbering: create a <form> with an onmouseover attribute and a child <input name='attributes'> to clobber form.attributes. For template bypass: create a <template> with innerHTML containing <img src=x onerror=...>. For shadow DOM bypass: create a <div> with attachShadow({mode:'open'}) and inject <img onerror=...> into the shadow root.
  4. Pass the foreign-realm node to DOMPurify: Call DOMPurify.sanitize(foreignNode, { IN_PLACE: true }) from the parent realm. Due to realm-bound instanceof failures, the sanitizer skips clobber detection, template recursion, and shadow DOM sanitization — the malicious payload survives.
  5. Trigger XSS execution: Insert the sanitized (but still malicious) node into the live DOM. For form clobbering, dispatch a mouseover event or wait for user interaction. For template content, call importNode(tpl.content, true) and append to the document. For shadow DOM, simply append the host element — the shadow root activates and onerror fires synchronously (DOMPurify Advisory).

Indicators of compromise

  • JavaScript Runtime: Unexpected values in window.__dompurify_xss, window.__dompurify_template_xss, or window.__dompurify_shadow_xss counters (used in PoC verification); unusual JavaScript execution originating from event handlers on <form>, <template>, or shadow DOM elements after DOMPurify sanitization.
  • DOM Inspection: Presence of onmouseover, onfocus, onclick, onerror, or action=javascript: attributes on <form> elements after sanitization; <template> elements retaining <img onerror=...> or <script> tags in their .content; shadow roots containing unsanitized event handler attributes.
  • Network: Unexpected outbound requests (e.g., to attacker-controlled domains) originating from browser sessions interacting with pages using DOMPurify with IN_PLACE: true; exfiltration of session cookies or tokens via XSS-triggered fetch/XHR calls.
  • Logs: Browser console errors or warnings related to cross-realm DOM operations; Content Security Policy (CSP) violation reports triggered by injected inline event handlers or scripts if CSP is enforced.

Mitigation and workarounds

The primary remediation is to upgrade DOMPurify to version 3.4.6 or later, which replaces realm-bound instanceof checks with realm-independent shape checks (e.g., nodeType === 11 for DocumentFragment, tag-name comparison for HTMLFormElement) across all affected sanitization branches (DOMPurify 3.4.6 Release, Patch Commit). If immediate patching is not possible, avoid using DOMPurify.sanitize() with the { IN_PLACE: true } option when the input node originates from a foreign realm (iframe, popup, or other same-origin realm); use string-input sanitization (DOMPurify.sanitize(dirtyString)) instead, which is not affected. Additionally, implement a strict Content Security Policy (CSP) with script-src restrictions to limit the impact of any XSS that does execute (Github Advisory).

Community reactions

The vulnerability was credited to researchers offset and Bankde, who reported the issue to cure53 and are acknowledged in the DOMPurify 3.4.6 release notes (DOMPurify 3.4.6 Release). Red Hat opened a tracking bug (Bugzilla #2500636) and assigned it medium severity, with 66 CC'd team members indicating broad internal awareness across Red Hat product lines (Red Hat Bugzilla). The advisory was also picked up by GitLab's advisory database and Tenable's plugin feeds, reflecting standard industry triage for a widely deployed npm library.

Additional resources


SourceThis report was generated using AI

Related JavaScript vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-w4hw-qcx7-56prCRITICAL9.2
  • JavaScript logoJavaScript
  • shescape
NoYesJul 24, 2026
GHSA-gm3r-q2wp-hw87HIGH8.7
  • JavaScript logoJavaScript
  • shescape
NoYesJul 24, 2026
GHSA-q53c-4prm-w95qMEDIUM6.3
  • JavaScript logoJavaScript
  • shescape
NoYesJul 24, 2026
GHSA-8q49-2h5h-434xMEDIUM5.9
  • JavaScript logoJavaScript
  • @frontmcp/adapters
NoYesJul 24, 2026
GHSA-3r53-75j5-3g7jMEDIUM5.6
  • JavaScript logoJavaScript
  • quasar
NoYesJul 24, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management