DOMPurify before 3.4.0 contains a logic error in the ADD_TAGS function where short-circuit evaluation allows forbidden tags to bypass…
VulnCheck·CWE-697·Published 2026-04-16
DOMPurify before 3.4.0 contains a logic error in the ADD_TAGS function where short-circuit evaluation allows forbidden tags to bypass FORBID_TAGS restrictions. Attackers can craft input containing tags listed in FORBID_TAGS that are also added via ADD_TAGS function, causing them to be retained in sanitized output.
DOMPurify before 3.4.0 contains a logic error in the ADD_TAGS function where short-circuit evaluation allows forbidden tags to bypass FORBID_TAGS restrictions. Attackers can craft input containing tags listed in FORBID_TAGS that are also added via ADD_TAGS function, causing them to be retained in sanitized output.
## 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)
## 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)
DOMPurify anterior a la versión 3.4.0 contiene un error lógico en la función ADD_TAGS donde la evaluación de cortocircuito permite que las etiquetas prohibidas eludan las restricciones de FORBID_TAGS. Los atacantes pueden elaborar una entrada que contenga etiquetas listadas en FORBID_TAGS que también se añaden a través de la función ADD_TAGS, provocando que se retengan en la salida saneada.
| Version | Type | Source | Base | Exp | Impact | Vector |
|---|---|---|---|---|---|---|
| 3.1 | Primary | cve.org | 6.1 | — | — | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N |
| 3.1 | Primary | cve.org | 6.1 | — | — | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N |
| 3.1 | Primary | NVD | 6.1 | 2.8 | 2.7 | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N |
| 3.1 | Secondary | NVD | 6.1 | 2.8 | 2.7 | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N |
| 4.0 | Primary | cve.org | 5.1 | — | — | CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N |
| 4.0 | Primary | cve.org | 5.1 | — | — | CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N |
| 4.0 | Secondary | GHSA | 5.3 | — | — | CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N |
| 4.0 | Secondary | NVD | 5.1 | — | — | CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X |
| 4.0 | Secondary | ENISA EUVD | 5.1 | — | — | CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N |