{"id":"CVE-2026-109345","aliases":["CLSA-2026-1791626851","CLSA-2026-1791626965","CLSA-2026-1791627235","CLSA-2026-1791627414","CLSA-2026-1791627570","CLSA-2026-1791627799","CLSA-2026-1791667159","CLSA-2026-1791667324","CLSA-2026-1791668940","CLSA-2026-1791795543","CLSA-2026-1791795654","CLSA-2026-1791798632","CLSA-2026-1791798802","CLSA-2026-1791799053","CLSA-2026-1791806404","CLSA-2026-1791806518","CLSA-2026-1791806624","CLSA-2026-1791814922","CLSA-2026-1791821318","CLSA-2026-1791821442","CLSA-2026-1791825519","CLSA-2026-1791846572","CLSA-2026-1791849675","CLSA-2026-1791888656","CLSA-2026-1791908220","CLSA-2026-1791988201","CLSA-2026-1792001523","CLSA-2026-1792150209","CLSA-2026-1792154118","CLSA-2026-1792155744","CLSA-2026-1792155851","CLSA-2026-1792156909","CLSA-2026-1792157349","CLSA-2026-1792157367","CLSA-2026-1792159109","CLSA-2026-1792159229","CLSA-2026-1792231043","CLSA-2026-1792508927","CLSA-2026-1792509241","CLSA-2026-1792933945","CLSA-2026-1793102164","DEBIAN-CVE-2026-109345","EUVD-2026-97647","GHSA-6688-9rhm-gjv2","GHSA-cjhx-p48c-gfm9","UBUNTU-CVE-2026-109345"],"status":"published","title":"DOMPurify before 3.4.16 XSS via IN_PLACE Returned Rawtext Root","description":"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.","severity":{"version":"4.0","score":5.1,"vector":"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","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.0025,"percentile":0.16494,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-79"],"published":"2026-10-05T23:43:53Z","modified":"2026-10-28T02:30:47Z","fixes":[{"ecosystem":"npm","package":"dompurify","fixed_in":["3.4.16"],"sources":["ghsa","osv"]},{"ecosystem":"TuxCare:npm","package":"dompurify","fixed_in":["2.3.0-tuxcare.6","2.4.7-tuxcare.6","2.5.8-tuxcare.8","2.5.9-tuxcare.8","3.0.3-tuxcare.6","3.1.6-tuxcare.9","3.2.3-tuxcare.5","3.2.7-tuxcare.4","3.4.8-tuxcare.5","3.2.6-tuxcare.1","3.3.3-tuxcare.1","3.1.4-tuxcare.1","3.0.2-tuxcare.1","2.0.8-tuxcare.1","3.1.3-tuxcare.1","2.4.0-tuxcare.6","3.0.1-tuxcare.1","2.3.10-tuxcare.1","3.1.2-tuxcare.1","2.3.3-tuxcare.1","3.1.1-tuxcare.1","3.1.0-tuxcare.1","3.0.11-tuxcare.1","3.0.9-tuxcare.1","3.0.8-tuxcare.1","3.0.6-tuxcare.1","3.0.5-tuxcare.1","3.0.4-tuxcare.1","3.4.14-tuxcare.2"],"sources":["osv"]},{"ecosystem":"Debian:14","package":"node-dompurify","fixed_in":["3.4.16+dfsg-1"],"sources":["osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"3.4.15"},{"fixed":"3.4.16"}]}]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.3.0-tuxcare.0"},{"fixed":"2.3.0-tuxcare.6"}]}],"versions":["2.3.0","2.3.0-tuxcare.1","2.3.0-tuxcare.2","2.3.0-tuxcare.3","2.3.0-tuxcare.4","2.3.0-tuxcare.5"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.4.7-tuxcare.0"},{"fixed":"2.4.7-tuxcare.6"}]}],"versions":["2.4.7","2.4.7-tuxcare.1","2.4.7-tuxcare.2","2.4.7-tuxcare.3","2.4.7-tuxcare.4","2.4.7-tuxcare.5"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.5.8-tuxcare.0"},{"fixed":"2.5.8-tuxcare.8"}]}],"versions":["2.5.8","2.5.8-tuxcare.1","2.5.8-tuxcare.2","2.5.8-tuxcare.3","2.5.8-tuxcare.4","2.5.8-tuxcare.5","2.5.8-tuxcare.6","2.5.8-tuxcare.7"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.5.9-tuxcare.0"},{"fixed":"2.5.9-tuxcare.8"}]}],"versions":["2.5.9","2.5.9-tuxcare.1","2.5.9-tuxcare.2","2.5.9-tuxcare.3","2.5.9-tuxcare.4","2.5.9-tuxcare.5","2.5.9-tuxcare.6","2.5.9-tuxcare.7"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.3-tuxcare.0"},{"fixed":"3.0.3-tuxcare.6"}]}],"versions":["3.0.3","3.0.3-tuxcare.1","3.0.3-tuxcare.2","3.0.3-tuxcare.3","3.0.3-tuxcare.4","3.0.3-tuxcare.5"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.1.6-tuxcare.0"},{"fixed":"3.1.6-tuxcare.9"}]}],"versions":["3.1.6","3.1.6-tuxcare.1","3.1.6-tuxcare.2","3.1.6-tuxcare.3","3.1.6-tuxcare.4","3.1.6-tuxcare.5","3.1.6-tuxcare.6","3.1.6-tuxcare.7","3.1.6-tuxcare.8"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.2.3-tuxcare.0"},{"fixed":"3.2.3-tuxcare.5"}]}],"versions":["3.2.3","3.2.3-tuxcare.1","3.2.3-tuxcare.2","3.2.3-tuxcare.3","3.2.3-tuxcare.4"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.2.7-tuxcare.0"},{"fixed":"3.2.7-tuxcare.4"}]}],"versions":["3.2.7","3.2.7-tuxcare.1","3.2.7-tuxcare.2","3.2.7-tuxcare.3"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.4.8-tuxcare.0"},{"fixed":"3.4.8-tuxcare.5"}]}],"versions":["3.4.8","3.4.8-tuxcare.1","3.4.8-tuxcare.2","3.4.8-tuxcare.3","3.4.8-tuxcare.4"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.2.6-tuxcare.0"},{"fixed":"3.2.6-tuxcare.1"}]}],"versions":["3.2.6"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.3.3-tuxcare.0"},{"fixed":"3.3.3-tuxcare.1"}]}],"versions":["3.3.3"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.1.4-tuxcare.0"},{"fixed":"3.1.4-tuxcare.1"}]}],"versions":["3.1.4"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.2-tuxcare.0"},{"fixed":"3.0.2-tuxcare.1"}]}],"versions":["3.0.2"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.8-tuxcare.0"},{"fixed":"2.0.8-tuxcare.1"}]}],"versions":["2.0.8"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.1.3-tuxcare.0"},{"fixed":"3.1.3-tuxcare.1"}]}],"versions":["3.1.3"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.4.0-tuxcare.0"},{"fixed":"2.4.0-tuxcare.6"}]}],"versions":["2.4.0","2.4.0-tuxcare.1","2.4.0-tuxcare.2","2.4.0-tuxcare.3","2.4.0-tuxcare.4","2.4.0-tuxcare.5"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.1-tuxcare.0"},{"fixed":"3.0.1-tuxcare.1"}]}],"versions":["3.0.1"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.3.10-tuxcare.0"},{"fixed":"2.3.10-tuxcare.1"}]}],"versions":["2.3.10"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.1.2-tuxcare.0"},{"fixed":"3.1.2-tuxcare.1"}]}],"versions":["3.1.2"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.3.3-tuxcare.0"},{"fixed":"2.3.3-tuxcare.1"}]}],"versions":["2.3.3"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.1.1-tuxcare.0"},{"fixed":"3.1.1-tuxcare.1"}]}],"versions":["3.1.1"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.1.0-tuxcare.0"},{"fixed":"3.1.0-tuxcare.1"}]}],"versions":["3.1.0"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.11-tuxcare.0"},{"fixed":"3.0.11-tuxcare.1"}]}],"versions":["3.0.11"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.9-tuxcare.0"},{"fixed":"3.0.9-tuxcare.1"}]}],"versions":["3.0.9"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.8-tuxcare.0"},{"fixed":"3.0.8-tuxcare.1"}]}],"versions":["3.0.8"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.6-tuxcare.0"},{"fixed":"3.0.6-tuxcare.1"}]}],"versions":["3.0.6"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.5-tuxcare.0"},{"fixed":"3.0.5-tuxcare.1"}]}],"versions":["3.0.5"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.4.5-tuxcare.0"},{"fixed":"3.4.5-tuxcare.2"}]}],"versions":["3.4.5","3.4.5-tuxcare.1"],"bundled":6},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.4.9-tuxcare.0"},{"fixed":"3.4.9-tuxcare.2"}]}],"versions":["3.4.9","3.4.9-tuxcare.1"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.4-tuxcare.0"},{"fixed":"3.0.4-tuxcare.1"}]}],"versions":["3.0.4"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.1.3-tuxcare.0"},{"fixed":"3.1.3-tuxcare.2"}]}],"versions":["3.1.3","3.1.3-tuxcare.1"],"bundled":12},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.1-tuxcare.0"},{"fixed":"3.0.1-tuxcare.2"}]}],"versions":["3.0.1","3.0.1-tuxcare.1"],"bundled":10},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.4.6-tuxcare.0"},{"fixed":"3.4.6-tuxcare.2"}]}],"versions":["3.4.6","3.4.6-tuxcare.1"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.4.7-tuxcare.0"},{"fixed":"3.4.7-tuxcare.2"}]}],"versions":["3.4.7","3.4.7-tuxcare.1"],"bundled":3},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.4.11-tuxcare.0"},{"fixed":"3.4.11-tuxcare.2"}]}],"versions":["3.4.11","3.4.11-tuxcare.1"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.4.10-tuxcare.0"},{"fixed":"3.4.10-tuxcare.2"}]}],"versions":["3.4.10","3.4.10-tuxcare.1"],"bundled":3},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.4.14-tuxcare.0"},{"fixed":"3.4.14-tuxcare.2"}]}],"versions":["3.4.14","3.4.14-tuxcare.1"]},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.4.13-tuxcare.0"},{"fixed":"3.4.13-tuxcare.1"}]}],"versions":["3.4.13"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.4.15-tuxcare.0"},{"fixed":"3.4.15-tuxcare.1"}]}],"versions":["3.4.15"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.4.0-tuxcare.0"},{"fixed":"3.4.0-tuxcare.1"}]}],"versions":["3.4.0"],"bundled":9},{"source":"osv","ecosystem":"TuxCare:npm","package":"dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.4.12-tuxcare.0"},{"fixed":"3.4.12-tuxcare.3"}]}],"versions":["3.4.12","3.4.12-tuxcare.1","3.4.12-tuxcare.2"],"bundled":3},{"source":"osv","ecosystem":"Debian:12","package":"node-dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.4.1+dfsg+~2.4.0-1","2.4.1+dfsg+~2.4.0-2","2.4.1+dfsg+~2.4.0-2+deb12u1","3.0.9+dfsg+~3.0.5-1","3.1.6+dfsg+~3.0.5-1","3.1.7+dfsg+~3.0.5-1","3.1.7+dfsg+~3.0.5-2","3.2.5+dfsg-1","3.3.2+dfsg-1","3.3.3+dfsg-1","3.3.3+dfsg-2","3.4.1+dfsg-1","3.4.12+dfsg-1","3.4.13+dfsg-1","3.4.13+dfsg-2","3.4.16+dfsg-1","3.4.2+dfsg-1","3.4.5+dfsg-1"]},{"source":"osv","ecosystem":"Debian:13","package":"node-dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3.1.7+dfsg+~3.0.5-2","3.2.5+dfsg-1","3.3.2+dfsg-1","3.3.3+dfsg-1","3.3.3+dfsg-2","3.4.1+dfsg-1","3.4.12+dfsg-1","3.4.13+dfsg-1","3.4.13+dfsg-2","3.4.16+dfsg-1","3.4.2+dfsg-1","3.4.5+dfsg-1"]},{"source":"osv","ecosystem":"Debian:14","package":"node-dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.4.16+dfsg-1"}]}],"versions":["3.1.7+dfsg+~3.0.5-2","3.2.5+dfsg-1","3.3.2+dfsg-1","3.3.3+dfsg-1","3.3.3+dfsg-2","3.4.1+dfsg-1","3.4.12+dfsg-1","3.4.13+dfsg-1","3.4.13+dfsg-2","3.4.2+dfsg-1","3.4.5+dfsg-1"]},{"source":"osv","ecosystem":"npm","package":"dompurify","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"3.4.16"}]}]},{"source":"osv","ecosystem":"Ubuntu:22.04:LTS","package":"node-dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.3.0+dfsg-2","2.3.3+dfsg-1"]},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"node-dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.4.1+dfsg+~2.4.0-1","3.0.9+dfsg+~3.0.5-1"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"node-dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3.3.3+dfsg-1","3.4.2+dfsg-1","3.4.5+dfsg-1","3.4.12+dfsg-1","3.4.13+dfsg-1","3.4.13+dfsg-2"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"node-dompurify","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3.1.7+dfsg+~3.0.5-2","3.3.3+dfsg-1"]}],"products":[{"vendor":"cure53","product":"dompurify"}],"references":[{"url":"https://github.com/cure53/DOMPurify/security/advisories/GHSA-6688-9rhm-gjv2","tags":["vendor-advisory","exploit","advisory","web","report"]},{"url":"https://www.vulncheck.com/advisories/dompurify-before-3.4.16-xss-via-in-place-returned-rawtext-root","tags":["third-party-advisory","advisory","report"]},{"url":"https://github.com/cure53/DOMPurify/pull/1636","tags":["web"]},{"url":"https://github.com/cure53/DOMPurify/commit/b9b9d80f7e401771c2ccaef5f45def7eec8f27d7","tags":["web"]},{"url":"https://github.com/cure53/DOMPurify/releases/tag/3.4.16","tags":["web"]},{"url":"https://github.com/advisories/GHSA-6688-9rhm-gjv2"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-109345","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-cjhx-p48c-gfm9"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/109xxx/CVE-2026-109345.json","tags":["advisory"]},{"url":"https://security-tracker.debian.org/tracker/CVE-2026-109345","tags":["advisory"]},{"url":"https://github.com/cure53/DOMPurify","tags":["package"]},{"url":"https://ubuntu.com/security/CVE-2026-109345","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-109345","tags":["report"]}],"sources":{"cve":[{"id":"CVE-2026-109345","title":"DOMPurify before 3.4.16 XSS via IN_PLACE Returned Rawtext Root","description":"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.","status":"published","published":"2026-10-12T16:05:29.905Z","modified":"2026-10-13T17:40:08.757Z","cvss":[{"version":"4.0","score":5.1,"vector":"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","level":"medium","assessor":"cna"},{"version":"3.1","score":6.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T14:20:11.581788Z"}],"euvd":[{"id":"EUVD-2026-97647","description":"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.","status":"published","published":"2026-10-12T16:05:29Z","modified":"2026-10-13T17:40:08Z","cvss":[{"version":"4.0","score":5.1,"vector":"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","level":"medium"}],"updated_at":"2026-11-02T17:27:19.128463Z"}],"ghsa":[{"id":"GHSA-cjhx-p48c-gfm9","title":"DOMPurify before 3.4.16 contains a cross-site scripting vulnerability that allows attackers to...","description":"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.","status":"published","published":"2026-10-12T18:31:51Z","modified":"2026-10-12T18:31:58Z","cvss":[{"version":"4.0","score":5.1,"vector":"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","level":"medium"},{"version":"3.1","score":6.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N","level":"medium"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T15:13:07.940274Z"},{"id":"GHSA-6688-9rhm-gjv2","title":"DOMPurify: IN_PLACE returns a force-removed rawtext root whose text carries attacker markup — pure HTML reparse executes","description":"## Environment\n\n- dompurify 3.4.15 (current npm release); reproduced independently on jsdom 30.0.1 and 29.1.1 (Node.js 20.x / 26.x)\n- Config: `DOMPurify.sanitize(node, { IN_PLACE: true })` on a Node input; `SAFE_FOR_XML` at its default (`true`)\n\n## Summary\n\nThe 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.\n\nBoth miss the rawtext **text-content** form. When the force-removed root is a rawtext element (`\u003cstyle\u003e`), 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 `\u003cstyle\u003e` 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.\n\nThe 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.\n\n## Steps to reproduce\n\n```js\nconst { JSDOM } = require('jsdom');\nconst createDOMPurify = require('dompurify');   // 3.4.15\n\nconst window = new JSDOM('').window;\nconst DOMPurify = createDOMPurify(window);\n\nconst styleRoot = window.document.createElement('style');\nstyleRoot.setAttribute('onclick', 'alert(1)');    // attribute payload\nstyleRoot.textContent = '\u003c/style\u003e\u003cimg src=x onerror=1\u003e';  // text payload\nwindow.document.body.appendChild(styleRoot);\n\nconst returned = DOMPurify.sanitize(styleRoot, { IN_PLACE: true });\n\nconsole.log(returned === styleRoot);                       // true (same node)\nconsole.log(styleRoot.parentNode === null);                // true (detached)\nconsole.log(styleRoot.outerHTML);\n// \u003cstyle\u003e\u003c/style\u003e\u003cimg src=x onerror=1\u003e\u003c/style\u003e\nconsole.log(styleRoot.getAttribute('onclick'));            // null  (attribute neutralized)\nconsole.log(styleRoot.textContent);                        // '\u003c/style\u003e\u003cimg src=x onerror=1\u003e' (text survives)\n\n// plain HTML reparse (no foreign-content context involved):\nconst probe = window.document.createElement('div');\nprobe.innerHTML = returned.outerHTML || styleRoot.outerHTML;\nconsole.log(probe.querySelectorAll('img').length);         // 1\nconsole.log(probe.querySelector('img').getAttribute('onerror')); // \"1\"\n```\n\nObserved on 3.4.15: one node, one call — the `onclick` **attribute** is neutralized while the **text** payload (`\u003c/style\u003e\u003cimg src=x onerror=1\u003e`) survives verbatim; serializing and re-parsing the returned node in plain HTML context materializes the `img` with the live `onerror` handler.\n\nContrast on the same Node input without `IN_PLACE`: `RETURN_DOM: true` → `\u003cbody\u003e\u003c/body\u003e`; `RETURN_DOM_FRAGMENT: true` → 0 children — the payload is fully sanitized away. The only difference is the IN_PLACE return path.\n\nContrast 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.\n\n## Root cause\n\n`_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**.\n\nThe IN_PLACE exit then hands the force-removed root back to the caller — the very node whose removal `DOMPurify.removed` just recorded (verified: `DOMPurify.removed.some(e =\u003e e.element === root)` is `true` on the returned instance). The 3.4.9 `_neutralizeSubtree` pass (line 1336) addresses only the attribute form — its own docstring: \"walks a removed subtree and strips every attribute\" (purpose: cancel queued resource events). Rawtext text content is out of its scope, so the removal that was performed *specifically to prevent reparse* is undone by returning the node: you removed it to stop the reparse, then returned it.\n\nDifferential (one node, one call, same removal path): the `onclick` attribute is neutralized by the existing pass while the text payload survives verbatim — the attribute axis is covered, the text axis is the gap.\n\n## Impact\n\nIdentical blast radius to the published IN_PLACE family: an application that sanitizes a Node in `IN_PLACE` mode and re-inserts (or serializes and then re-inserts) the result materializes attacker markup in plain HTML context: script execution in the page. Moving the returned node via `appendChild` alone is safe; the round trip through serialization is what fires the payload. No foreign-content context is required with the close-tag payload.\n\n## Affected versions\n\n- Verified live: 3.4.15 (current).\n- Source-verified: the attribute-only `_neutralizeSubtree` and the IN_PLACE return path are present in 3.4.9–3.4.14; releases before 3.4.9 predate the fix entirely (unconditional return; individual pre-3.4.9 releases not dynamically tested).\n- Per cure53 advisory convention the affected range is reported as `\u003c= 3.4.15` (current at time of writing).\n\n## Suggested remediation\n\n**Primary (root-cause, covers every form):** at the IN_PLACE exit, check whether the returned root was recorded during sanitization — `DOMPurify.removed.some(e =\u003e e.element === root)` — and fail closed: throw the same `TypeError` style used by the 3.4.9 detach guard (\"a node selected for removal could not be safely returned; refusing to sanitize in place\"), or return `null`. This is consistent with the existing fail-closed design and covers all present and future root-kill reasons in one check.\n\n**Secondary (form-specific):** extend `_neutralizeSubtree` to neutralize **text content of rawtext descendants** — the elements in `LITERAL_TEXT_ELEMENT_NAMES` (`style`, `script`, `xmp`, `iframe`, `noembed`, `noframes`, `plaintext`, `noscript`) — by rewriting `textContent` to a defanged form, matching the probe coverage of `_isUnsafeNode`/`LITERAL_TEXT_CLOSE`.\n\nA regression test asserting that a force-removed rawtext root comes back with no `/\u003c[/\\w!]/` match in `textContent` (and is not returned at all under the primary fix) prevents re-introduction.\n\n## Prior art / differentiation\n\n- GHSA-r47g-fvhr-h676 (fixed 3.4.6): clobbered-form **root** removal — different trigger; this report's root is a normal allowlisted `style` element killed by the text probe.\n- GHSA-55q2-fjhq-7xh7 (low): IN_PLACE **hook removal** leaves a detached subtree executable — the attribute-form twin (hook-stripped subtree retains onload-class handlers). This report's rawtext **text** form is not covered by `_neutralizeSubtree`'s attribute stripping and is not that advisory.\n- GHSA-h8r8-wccr-v5f2 (medium): mXSS via re-contextualization in the standard (non-IN_PLACE) serialize path — different mechanism; IN_PLACE is not involved.\n- The 3.4.9 release notes credit @mozfreedyb for the IN_PLACE handling improvements that this residual escapes on the text axis.\n\n## Applicability scope (stated up front)\n\nThe payload materializes when the application **serializes and re-parses** the sanitizer output (`innerHTML` assignment, template rendering, markdown/HTML round trips) or otherwise consumes the returned node's markup. Moving the returned node via `appendChild` alone does not trigger it. Applications that pass **live, connected attacker trees** into `IN_PLACE` are explicitly warned against by upstream's own source comment; this report concerns the serialize-and-reinsert consumption pattern that the IN_PLACE mode exists to serve.","status":"published","published":"2026-10-05T23:43:53Z","modified":"2026-10-05T23:43:54Z","cwes":["CWE-79"],"updated_at":"2026-11-02T14:41:27.036917Z"}],"nvd":[{"id":"CVE-2026-109345","description":"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.","status":"published","published":"2026-10-12T17:17:31.217Z","modified":"2026-10-16T17:27:24.847Z","cvss":[{"version":"4.0","score":5.1,"vector":"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","level":"medium","assessor":"secondary"},{"version":"3.1","score":6.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N","level":"medium","assessor":"secondary"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T14:12:56.310333Z"}],"osv":[{"id":"CVE-2026-109345","title":"DOMPurify before 3.4.16 XSS via IN_PLACE Returned Rawtext Root","description":"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.","status":"published","published":"2026-10-12T16:05:29.905Z","modified":"2026-10-28T02:30:47.677777305Z","cvss":[{"version":"4.0","score":5.1,"vector":"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","level":"medium"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T15:44:55.279797Z"},{"id":"DEBIAN-CVE-2026-109345","description":"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.","status":"published","published":"2026-10-12T17:17:31.217Z","modified":"2026-10-23T17:47:24.590821156Z","cvss":[{"version":"4.0","score":5.1,"vector":"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","level":"medium"}],"updated_at":"2026-11-02T15:45:49.381767Z"},{"id":"UBUNTU-CVE-2026-109345","description":"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.","status":"published","published":"2026-10-12T17:17:00Z","modified":"2026-10-17T12:58:45.014380615Z","cvss":[{"version":"3.1","score":6.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N","level":"medium"},{"version":"4.0","score":5.1,"vector":"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","level":"medium"}],"updated_at":"2026-11-02T16:55:59.130573Z"},{"id":"CLSA-2026-1791626851","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.3.0-tuxcare.6.","status":"published","published":"2026-10-10T10:07:31Z","modified":"2026-10-15T09:48:04.445645883Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791626965","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.4.7-tuxcare.6.","status":"published","published":"2026-10-10T10:09:25Z","modified":"2026-10-15T09:48:04.416655825Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791627235","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.5.8-tuxcare.8.","status":"published","published":"2026-10-10T10:13:55Z","modified":"2026-10-15T09:47:58.462495667Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791627414","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.5.9-tuxcare.8.","status":"published","published":"2026-10-10T10:16:54Z","modified":"2026-10-15T09:48:00.14112387Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791627570","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.3-tuxcare.6.","status":"published","published":"2026-10-10T10:19:30Z","modified":"2026-10-15T09:47:58.477890957Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791627799","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.1.6-tuxcare.9.","status":"published","published":"2026-10-10T10:23:19Z","modified":"2026-10-15T09:47:58.454695854Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791667159","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.2.3-tuxcare.5.","status":"published","published":"2026-10-10T21:19:19Z","modified":"2026-10-15T09:47:39.817645267Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791667324","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.2.7-tuxcare.4.","status":"published","published":"2026-10-10T21:22:04Z","modified":"2026-10-15T09:45:40.487925502Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791668940","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.4.8-tuxcare.5.","status":"published","published":"2026-10-10T21:49:00Z","modified":"2026-10-15T09:47:39.693212954Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791795543","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.2.6-tuxcare.1.","status":"published","published":"2026-10-12T08:59:03Z","modified":"2026-10-15T09:47:39.874417195Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791795654","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.3.3-tuxcare.1.","status":"published","published":"2026-10-12T09:00:54Z","modified":"2026-10-15T09:47:40.032969191Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791798632","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.1.4-tuxcare.1.","status":"published","published":"2026-10-12T09:50:32Z","modified":"2026-10-15T09:47:39.926233453Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791798802","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.2-tuxcare.1.","status":"published","published":"2026-10-12T09:53:22Z","modified":"2026-10-15T09:47:40.202071608Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791799053","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.0.8-tuxcare.1.","status":"published","published":"2026-10-12T09:57:34Z","modified":"2026-10-15T09:47:40.125046868Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791806404","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.1.3-tuxcare.1.","status":"published","published":"2026-10-12T12:00:04Z","modified":"2026-10-15T09:47:39.840117824Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791806518","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.4.0-tuxcare.6.","status":"published","published":"2026-10-12T12:01:58Z","modified":"2026-10-15T09:47:58.571017784Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791806624","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.1-tuxcare.1.","status":"published","published":"2026-10-12T12:03:44Z","modified":"2026-10-15T09:47:40.248247319Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791814922","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.3.10-tuxcare.1.","status":"published","published":"2026-10-12T14:22:02Z","modified":"2026-10-15T09:47:40.200959999Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791821318","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.1.2-tuxcare.1.","status":"published","published":"2026-10-12T16:08:38Z","modified":"2026-10-15T09:47:58.581366309Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791821442","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 2.3.3-tuxcare.1.","status":"published","published":"2026-10-12T16:10:42Z","modified":"2026-10-15T09:47:40.332021727Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791825519","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.1.1-tuxcare.1.","status":"published","published":"2026-10-12T17:18:39Z","modified":"2026-10-15T09:47:59.487867808Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791846572","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.1.0-tuxcare.1.","status":"published","published":"2026-10-12T23:09:32Z","modified":"2026-10-15T09:47:53.554233215Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791849675","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.11-tuxcare.1.","status":"published","published":"2026-10-13T00:01:15Z","modified":"2026-10-15T09:45:52.242452937Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791888656","title":"TuxCare security update for dompurify (2 CVEs)","description":"TuxCare rebuilt dompurify to address 2 CVEs. Fixed in 3.0.9-tuxcare.1.","status":"published","published":"2026-10-13T10:50:56Z","modified":"2026-10-15T09:47:21.180431121Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791908220","title":"TuxCare security update for dompurify (2 CVEs)","description":"TuxCare rebuilt dompurify to address 2 CVEs. Fixed in 3.0.8-tuxcare.1.","status":"published","published":"2026-10-13T16:17:00Z","modified":"2026-10-15T09:48:00.217673169Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1791988201","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.6-tuxcare.1.","status":"published","published":"2026-10-14T14:30:01Z","modified":"2026-10-15T09:47:40.4874086Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1792001523","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.5-tuxcare.1.","status":"published","published":"2026-10-14T18:12:03Z","modified":"2026-10-15T09:47:40.388065595Z","updated_at":"2026-11-02T15:43:50.599064Z"},{"id":"CLSA-2026-1792150209","title":"TuxCare security update for dompurify (9 CVEs)","description":"TuxCare rebuilt dompurify to address 9 CVEs. Fixed in 3.4.5-tuxcare.2.","status":"published","published":"2026-10-16T11:30:09Z","modified":"2026-10-16T12:15:02.208574712Z","updated_at":"2026-11-02T15:43:50.949147Z"},{"id":"CLSA-2026-1792154118","title":"TuxCare security update for dompurify (2 CVEs)","description":"TuxCare rebuilt dompurify to address 2 CVEs. Fixed in 3.4.9-tuxcare.2.","status":"published","published":"2026-10-16T12:35:18Z","modified":"2026-10-16T16:30:44.521578021Z","updated_at":"2026-11-02T15:43:50.949147Z"},{"id":"CLSA-2026-1792155744","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.0.4-tuxcare.1.","status":"published","published":"2026-10-16T13:02:24Z","modified":"2026-10-16T16:30:44.116455841Z","updated_at":"2026-11-02T15:43:50.949147Z"},{"id":"CLSA-2026-1792155851","title":"TuxCare security update for dompurify (12 CVEs)","description":"TuxCare rebuilt dompurify to address 12 CVEs. Fixed in 3.1.3-tuxcare.2.","status":"published","published":"2026-10-16T13:04:11Z","modified":"2026-10-21T20:43:23.163914038Z","updated_at":"2026-11-02T15:43:50.949147Z"},{"id":"CLSA-2026-1792156909","title":"TuxCare security update for dompurify (10 CVEs)","description":"TuxCare rebuilt dompurify to address 10 CVEs. Fixed in 3.0.1-tuxcare.2.","status":"published","published":"2026-10-16T13:21:49Z","modified":"2026-10-21T20:43:22.31228165Z","updated_at":"2026-11-02T15:43:50.949147Z"},{"id":"CLSA-2026-1792157349","title":"TuxCare security update for dompurify (5 CVEs)","description":"TuxCare rebuilt dompurify to address 5 CVEs. Fixed in 3.4.6-tuxcare.2.","status":"published","published":"2026-10-16T13:29:09Z","modified":"2026-10-16T16:30:25.229397141Z","updated_at":"2026-11-02T15:43:50.949147Z"},{"id":"CLSA-2026-1792157367","title":"TuxCare security update for dompurify (4 CVEs)","description":"TuxCare rebuilt dompurify to address 4 CVEs. Fixed in 3.4.7-tuxcare.2.","status":"published","published":"2026-10-16T13:29:27Z","modified":"2026-10-16T16:30:25.229723333Z","updated_at":"2026-11-02T15:43:50.949147Z"},{"id":"CLSA-2026-1792159109","title":"TuxCare security update for dompurify (2 CVEs)","description":"TuxCare rebuilt dompurify to address 2 CVEs. Fixed in 3.4.11-tuxcare.2.","status":"published","published":"2026-10-16T13:58:29Z","modified":"2026-10-16T16:30:24.618322061Z","updated_at":"2026-11-02T15:43:50.949147Z"},{"id":"CLSA-2026-1792159229","title":"TuxCare security update for dompurify (3 CVEs)","description":"TuxCare rebuilt dompurify to address 3 CVEs. Fixed in 3.4.10-tuxcare.2.","status":"published","published":"2026-10-16T14:00:29Z","modified":"2026-10-16T16:30:24.871695064Z","updated_at":"2026-11-02T15:43:50.949147Z"},{"id":"CLSA-2026-1792231043","title":"TuxCare security update for dompurify (1 CVE)","description":"TuxCare rebuilt dompurify to address 1 CVE. Fixed in 3.4.14-tuxcare.2.","status":"published","published":"2026-10-17T09:57:23Z","modified":"2026-10-17T13:09:25.378293749Z","updated_at":"2026-11-02T15:43:52.011757Z"},{"id":"CLSA-2026-1792508927","title":"TuxCare security update for dompurify (2 CVEs)","description":"TuxCare rebuilt dompurify to address 2 CVEs. Fixed in 3.4.13-tuxcare.1.","status":"published","published":"2026-10-20T15:08:47Z","modified":"2026-10-20T19:30:16.3823655Z","updated_at":"2026-11-02T15:43:54.378946Z"},{"id":"CLSA-2026-1792509241","title":"TuxCare security update for dompurify (2 CVEs)","description":"TuxCare rebuilt dompurify to address 2 CVEs. Fixed in 3.4.15-tuxcare.1.","status":"published","published":"2026-10-20T15:14:01Z","modified":"2026-10-20T19:30:16.374998439Z","updated_at":"2026-11-02T15:43:54.378946Z"},{"id":"CLSA-2026-1792933945","title":"TuxCare security update for dompurify (12 CVEs)","description":"TuxCare rebuilt dompurify to address 12 CVEs. Fixed in 3.4.0-tuxcare.1.","status":"published","published":"2026-10-25T13:12:25Z","modified":"2026-10-25T19:15:03.066551076Z","updated_at":"2026-11-02T15:43:54.981307Z"},{"id":"CLSA-2026-1793102164","title":"TuxCare security update for dompurify (4 CVEs)","description":"TuxCare rebuilt dompurify to address 4 CVEs. Fixed in 3.4.12-tuxcare.3.","status":"published","published":"2026-10-27T11:56:04Z","modified":"2026-10-27T13:30:18.441793863Z","updated_at":"2026-11-02T15:43:55.34846Z"},{"id":"GHSA-6688-9rhm-gjv2","title":"DOMPurify: IN_PLACE returns a force-removed rawtext root whose text carries attacker markup — pure HTML reparse executes","description":"## Environment\n\n- dompurify 3.4.15 (current npm release); reproduced independently on jsdom 30.0.1 and 29.1.1 (Node.js 20.x / 26.x)\n- Config: `DOMPurify.sanitize(node, { IN_PLACE: true })` on a Node input; `SAFE_FOR_XML` at its default (`true`)\n\n## Summary\n\nThe 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.\n\nBoth miss the rawtext **text-content** form. When the force-removed root is a rawtext element (`\u003cstyle\u003e`), 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 `\u003cstyle\u003e` 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.\n\nThe 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.\n\n## Steps to reproduce\n\n```js\nconst { JSDOM } = require('jsdom');\nconst createDOMPurify = require('dompurify');   // 3.4.15\n\nconst window = new JSDOM('').window;\nconst DOMPurify = createDOMPurify(window);\n\nconst styleRoot = window.document.createElement('style');\nstyleRoot.setAttribute('onclick', 'alert(1)');    // attribute payload\nstyleRoot.textContent = '\u003c/style\u003e\u003cimg src=x onerror=1\u003e';  // text payload\nwindow.document.body.appendChild(styleRoot);\n\nconst returned = DOMPurify.sanitize(styleRoot, { IN_PLACE: true });\n\nconsole.log(returned === styleRoot);                       // true (same node)\nconsole.log(styleRoot.parentNode === null);                // true (detached)\nconsole.log(styleRoot.outerHTML);\n// \u003cstyle\u003e\u003c/style\u003e\u003cimg src=x onerror=1\u003e\u003c/style\u003e\nconsole.log(styleRoot.getAttribute('onclick'));            // null  (attribute neutralized)\nconsole.log(styleRoot.textContent);                        // '\u003c/style\u003e\u003cimg src=x onerror=1\u003e' (text survives)\n\n// plain HTML reparse (no foreign-content context involved):\nconst probe = window.document.createElement('div');\nprobe.innerHTML = returned.outerHTML || styleRoot.outerHTML;\nconsole.log(probe.querySelectorAll('img').length);         // 1\nconsole.log(probe.querySelector('img').getAttribute('onerror')); // \"1\"\n```\n\nObserved on 3.4.15: one node, one call — the `onclick` **attribute** is neutralized while the **text** payload (`\u003c/style\u003e\u003cimg src=x onerror=1\u003e`) survives verbatim; serializing and re-parsing the returned node in plain HTML context materializes the `img` with the live `onerror` handler.\n\nContrast on the same Node input without `IN_PLACE`: `RETURN_DOM: true` → `\u003cbody\u003e\u003c/body\u003e`; `RETURN_DOM_FRAGMENT: true` → 0 children — the payload is fully sanitized away. The only difference is the IN_PLACE return path.\n\nContrast 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.\n\n## Root cause\n\n`_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**.\n\nThe IN_PLACE exit then hands the force-removed root back to the caller — the very node whose removal `DOMPurify.removed` just recorded (verified: `DOMPurify.removed.some(e =\u003e e.element === root)` is `true` on the returned instance). The 3.4.9 `_neutralizeSubtree` pass (line 1336) addresses only the attribute form — its own docstring: \"walks a removed subtree and strips every attribute\" (purpose: cancel queued resource events). Rawtext text content is out of its scope, so the removal that was performed *specifically to prevent reparse* is undone by returning the node: you removed it to stop the reparse, then returned it.\n\nDifferential (one node, one call, same removal path): the `onclick` attribute is neutralized by the existing pass while the text payload survives verbatim — the attribute axis is covered, the text axis is the gap.\n\n## Impact\n\nIdentical blast radius to the published IN_PLACE family: an application that sanitizes a Node in `IN_PLACE` mode and re-inserts (or serializes and then re-inserts) the result materializes attacker markup in plain HTML context: script execution in the page. Moving the returned node via `appendChild` alone is safe; the round trip through serialization is what fires the payload. No foreign-content context is required with the close-tag payload.\n\n## Affected versions\n\n- Verified live: 3.4.15 (current).\n- Source-verified: the attribute-only `_neutralizeSubtree` and the IN_PLACE return path are present in 3.4.9–3.4.14; releases before 3.4.9 predate the fix entirely (unconditional return; individual pre-3.4.9 releases not dynamically tested).\n- Per cure53 advisory convention the affected range is reported as `\u003c= 3.4.15` (current at time of writing).\n\n## Suggested remediation\n\n**Primary (root-cause, covers every form):** at the IN_PLACE exit, check whether the returned root was recorded during sanitization — `DOMPurify.removed.some(e =\u003e e.element === root)` — and fail closed: throw the same `TypeError` style used by the 3.4.9 detach guard (\"a node selected for removal could not be safely returned; refusing to sanitize in place\"), or return `null`. This is consistent with the existing fail-closed design and covers all present and future root-kill reasons in one check.\n\n**Secondary (form-specific):** extend `_neutralizeSubtree` to neutralize **text content of rawtext descendants** — the elements in `LITERAL_TEXT_ELEMENT_NAMES` (`style`, `script`, `xmp`, `iframe`, `noembed`, `noframes`, `plaintext`, `noscript`) — by rewriting `textContent` to a defanged form, matching the probe coverage of `_isUnsafeNode`/`LITERAL_TEXT_CLOSE`.\n\nA regression test asserting that a force-removed rawtext root comes back with no `/\u003c[/\\w!]/` match in `textContent` (and is not returned at all under the primary fix) prevents re-introduction.\n\n## Prior art / differentiation\n\n- GHSA-r47g-fvhr-h676 (fixed 3.4.6): clobbered-form **root** removal — different trigger; this report's root is a normal allowlisted `style` element killed by the text probe.\n- GHSA-55q2-fjhq-7xh7 (low): IN_PLACE **hook removal** leaves a detached subtree executable — the attribute-form twin (hook-stripped subtree retains onload-class handlers). This report's rawtext **text** form is not covered by `_neutralizeSubtree`'s attribute stripping and is not that advisory.\n- GHSA-h8r8-wccr-v5f2 (medium): mXSS via re-contextualization in the standard (non-IN_PLACE) serialize path — different mechanism; IN_PLACE is not involved.\n- The 3.4.9 release notes credit @mozfreedyb for the IN_PLACE handling improvements that this residual escapes on the text axis.\n\n## Applicability scope (stated up front)\n\nThe payload materializes when the application **serializes and re-parses** the sanitizer output (`innerHTML` assignment, template rendering, markdown/HTML round trips) or otherwise consumes the returned node's markup. Moving the returned node via `appendChild` alone does not trigger it. Applications that pass **live, connected attacker trees** into `IN_PLACE` are explicitly warned against by upstream's own source comment; this report concerns the serialize-and-reinsert consumption pattern that the IN_PLACE mode exists to serve.","status":"published","published":"2026-10-05T23:43:53Z","modified":"2026-10-13T02:56:32.03282437Z","cwes":["CWE-79"],"updated_at":"2026-11-02T15:46:39.266402Z"}]}}
