GHSA-39q2-94rc-95cp
NoneCVSS
—
EPSS
—
Published
Apr 16, 2026
CISA due date
—
Cloudanix analysis
Some websites using this library may fail to remove unsafe user-submitted content, allowing attackers to make malicious content appear to other users.
- Exploitation
- Requires User Interaction
- Attacker needs
- None
- Complexity
- Moderate
- Impact
- Data Exposure
- Component
- Library
- Class
- XSS
- Remediation
- Upgrade
- Effort
- Low
- Patch risk
- Low
What it actually does
DOMPurify versions before 3.4.0 contain a sanitization logic flaw in the interaction between ADD_TAGS and FORBID_TAGS when ADD_TAGS is supplied as a function. Because of short-circuit evaluation, a tag that should be blocked by FORBID_TAGS can be allowed when the ADD_TAGS callback permits it. Applications that rely on DOMPurify to neutralize untrusted HTML may therefore render attacker-controlled elements that developers explicitly intended to forbid, creating a cross-site scripting or HTML injection risk depending on the surrounding application context, allowed attributes, browser behavior, and downstream rendering logic.
Why it matters to the business
If an application uses vulnerable DOMPurify configurations to sanitize user-supplied HTML, attackers may be able to inject active or unsafe content into pages viewed by users. This can lead to account takeover, session theft, fraudulent user actions, data exposure, defacement, or abuse of trusted application workflows. The issue is especially relevant for products with rich-text editors, comments, messaging, CMS features, ticketing systems, email rendering, documentation platforms, or any workflow that stores and later displays sanitized HTML. The package is fixed in dompurify 3.4.0, and remediation should be prioritized where DOMPurify is used with custom ADD_TAGS and FORBID_TAGS policies.
How an attack unfolds
An attacker first identifies an application feature that accepts HTML-like input and later displays it after sanitization with DOMPurify. The attacker then crafts markup containing a tag that the application intended to block through FORBID_TAGS. If the application also configures ADD_TAGS as a function, the attacker attempts to choose a tag name or input pattern that causes the ADD_TAGS callback to return an allowing result before the FORBID_TAGS restriction is enforced. If successful, the forbidden tag survives sanitization and is inserted into the DOM. The attacker then combines the allowed tag with permitted attributes, browser parsing behavior, DOM clobbering opportunities, framework-specific rendering behavior, or other application-specific gadgets to execute script or alter page behavior. Successful exploitation generally depends on the application’s sanitizer configuration and where the sanitized output is rendered; the advisory does not indicate known public exploit maturity or exploitation in CISA KEV.
How to fix it
Upgrade dompurify to version 3.4.0 or later wherever it is used. For npm-based projects, update package manifests and lockfiles, rebuild, and redeploy all affected frontend and server-side rendering artifacts. Review any DOMPurify configuration that uses ADD_TAGS as a function together with FORBID_TAGS; ensure deny-list decisions cannot be overridden by custom allow-list logic. As a defense-in-depth measure, prefer strict allow-list sanitization, avoid dynamically allowing tags based on untrusted input, restrict allowed attributes and URI schemes, and deploy a Content Security Policy that prevents inline script execution where feasible. If immediate upgrade is not possible, remove function-based ADD_TAGS usage or ensure the callback explicitly rejects every tag listed in FORBID_TAGS before returning an allow decision.
How to confirm the fix worked
Confirm that all dependency manifests, package-lock.json, npm-shrinkwrap.json, yarn.lock, pnpm-lock.yaml, bundled assets, container images, and deployed artifacts resolve dompurify to 3.4.0 or later. Run dependency scanning or `npm ls dompurify` in each affected project to verify no vulnerable transitive or direct copy remains. Add regression tests for sanitizer configurations that combine ADD_TAGS as a function with FORBID_TAGS, specifically asserting that every forbidden tag is removed even if the ADD_TAGS callback would otherwise allow it. Validate built frontend bundles if DOMPurify is vendored or bundled, because the runtime version may differ from the source manifest. Test representative rich-text inputs in staging and confirm forbidden tags are stripped from rendered output.
Typical attack path
- Find a page or API endpoint that accepts user-controlled HTML or rich text.
- Submit probing payloads to determine whether the application uses DOMPurify and whether custom tag allow/deny rules are present.
- Craft markup using a tag that should be blocked by FORBID_TAGS but may be allowed by an ADD_TAGS function callback.
- Store or reflect the payload so it is rendered in another user’s browser after sanitization.
- Use surviving markup and any permitted attributes or browser/framework behavior to trigger script execution or malicious UI manipulation.
- Steal user data, perform actions as the victim, redirect users, or persist malicious content in application-controlled pages.
How to detect it
To assess prior exploitation, review application logs and stored content for HTML submissions that include tags explicitly listed in the application’s FORBID_TAGS configuration, especially around rich-text editors, comments, messages, profile fields, CMS pages, support tickets, and email/template rendering features. Compare raw submitted content with sanitized/rendered output where available; exploitation is indicated by forbidden tags surviving sanitization. Search web access logs, API request bodies, WAF events, and application audit logs for repeated HTML probing, unusual tag names, encoded markup, and payloads that combine forbidden tags with event-handler attributes, javascript: URLs, SVG/MathML constructs, iframe/object/embed/style tags, or template/framework expressions. Also review client-side error reporting, CSP violation reports, and user reports of unexpected redirects, pop-ups, defacement, or unauthorized actions following viewing of user-generated content. There are no universal network indicators because successful exploitation is highly dependent on application-specific DOMPurify configuration and accepted HTML features.
- ADD_TAGS
- FORBID_TAGS
- <script
- </script>
- <iframe
- </iframe>
- <object
- </object>
- <embed
- <svg
- </svg>
- <math
- </math>
- onerror=
- onload=
- onclick=
- onmouseover=
- javascript:
- data:text/html
- DOMPurify.sanitize
- content-security-policy violation
- blocked-uri
What your security team should do
- Inventory applications and packages that include dompurify, with priority on internet-facing systems and features that accept or render user-generated HTML.
- Upgrade all direct and transitive dompurify usage to 3.4.0 or later, then rebuild and redeploy affected assets.
- Search code for DOMPurify configurations using ADD_TAGS as a function, especially when combined with FORBID_TAGS, and review them for unsafe policy logic.
- Add automated dependency checks to fail builds when dompurify resolves below 3.4.0.
- Add sanitizer regression tests for application-specific forbidden tags and rich-text workflows.
- Review recent user-generated HTML submissions in high-risk features for suspicious forbidden tags or script-like payloads.
- Deploy or tighten Content Security Policy controls to reduce exploitability if sanitizer bypasses occur.
- Monitor security advisories for DOMPurify and related rich-text/editor dependencies because sanitizer bypasses often depend on browser and framework behavior.
The record
DOMPurify's ADD_TAGS function form bypasses FORBID_TAGS due to short-circuit evaluation
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| npm | dompurify | 0 | 3.4.0 |
Related vulnerabilities
- 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
- GHSA-r47g-fvhr-h676 DOMPurify: IN_PLACE mode preserves attributes of a clobbered root element, allowing XSS… Also affects dompurify