Packages / dompurify / Security

ModerateVulnerabilityGHSA-39q2-94rc-95cpCVE-2026-65903Published 16 Apr 2026

DOMPurify's ADD_TAGS function form bypasses FORBID_TAGS due to short-circuit evaluation

Affected releases · dompurify

  • 3.x3.0.0 – 3.3.3Fixed in 3.4.0
  • 2.x2.0.0 – 2.5.9No fix on this line yet
  • 1.x and older0.4.0 – 1.1.1No fix, no longer updated

On 3.x, the newest line:

npm install dompurify@3.4.0
3.x
  1. Affected

    3.0.0 – 3.3.3

    32 releases

  2. Fixed

    3.4.0 – 3.4.17

    18 releases, latest

2.x
  1. Affected

    2.0.0 – 2.5.9

    63 releases

1.x
  1. Affected

    1.0.0 – 1.1.1

    14 releases

0.x
  1. Affected

    0.4.0 – 0.9.0

    29 releases

156 stable releases of dompurify, oldest to newest, one row per major.

Is your project affected?

Paste your package.json, or type the range you declare for dompurify. It is read in your browser and sent nowhere.

What happens

Summary

In src/purify.ts:1117-1123, ADD_TAGS as a function (via EXTRA_ELEMENT_HANDLING.tagCheck) bypasses FORBID_TAGS due to short-circuit evaluation.

The condition:

!(tagCheck(tagName)) && (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName])

When tagCheck(tagName) returns true, the entire condition is false and the element is kept — FORBID_TAGS[tagName] is never evaluated.

Inconsistency

This contradicts the attribute-side pattern at line 1214 where FORBID_ATTR explicitly wins first:

if (FORBID_ATTR[lcName]) { continue; }

For tags, FORBID should also take precedence over ADD.

Impact

Applications using both ADD_TAGS as a function and FORBID_TAGS simultaneously get unexpected behavior — forbidden tags are allowed through. Config-dependent but a genuine logic inconsistency.

Suggested Fix

Check FORBID_TAGS before tagCheck:

if (FORBID_TAGS[tagName]) { /* remove */ }
else if (tagCheck(tagName) || ALLOWED_TAGS[tagName]) { /* keep */ }

Affected Version

v3.3.3 (commit 883ac15)