[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"repo-stars":3,"vuln-GHSA-VXR8-FQ34-VVX9":6},{"stargazers_count":4,"fetched_at":5},8,"2026-09-19T17:35:29.592Z",{"id":7,"descriptions":8,"cisa":9,"weaknesses":10,"exploits":11,"aliases":12,"duplicate_of":9,"upstream":13,"downstream":14,"duplicates":17,"related":18,"reserved_at":9,"published_at":23,"modified_at":24,"state":9,"summary":25,"references_raw":27,"kevs":39,"epss":9,"epss_history":40,"metrics":41,"affected":46},"GHSA-VXR8-FQ34-VVX9","DOMPurify: Trusted Types policy survives `clearConfig()` and can poison later `RETURN_TRUSTED_TYPE` output\n\n## Impact\n\nA DOMPurify instance that is reused across trust boundaries can stay bound to a previously supplied `TRUSTED_TYPES_POLICY` even after `clearConfig()` is called. A later caller that requests `RETURN_TRUSTED_TYPE` receives a `TrustedHTML` object created by the old policy, not by a clean default configuration.\n\nIf the old policy is unsafe or controlled by a less-trusted integration, this turns a later \"default\" sanitize call into script execution at a Trusted Types sink. `TRUSTED_TYPES_POLICY: null` on the later call also does not clear the retained policy.\n[dompurify-trusted-types-policy-survives-clearconfig-poc.js](https://github.com/user-attachments/files/28604913/dompurify-trusted-types-policy-survives-clearconfig-poc.js)\n\n\n## Affected version\n\nTested against DOMPurify `3.4.8`, repository commit `825e617753ac1169306a542d3174a77f717a0cf6`.\n\n## Root cause\n\n`_parseConfig()` overwrites `trustedTypesPolicy` when `cfg.TRUSTED_TYPES_POLICY` is truthy, but the default/null path only initializes the internal policy when `trustedTypesPolicy === undefined`. Once a custom policy has been set, later default config parsing leaves it in place.\n\nRelevant code:\n\n- `src/purify.ts:786-812` accepts and stores `cfg.TRUSTED_TYPES_POLICY`.\n- `src/purify.ts:813-832` does not reset an existing policy when config has no policy or has `TRUSTED_TYPES_POLICY: null`.\n- `src/purify.ts:2123-2125` signs the final serialized HTML with the retained policy when `RETURN_TRUSTED_TYPE` is true.\n- `src/purify.ts:2133-2136` `clearConfig()` only clears `CONFIG` and `SET_CONFIG`; it does not reset `trustedTypesPolicy` or `emptyHTML`.\n\n## Local PoC\n\nRun from the DOMPurify checkout, or set `DOMPURIFY_REPO`:\n\n```bash\nnode /home/dompurify-trusted-types-policy-survives-clearconfig-poc.js\n```\n\nObserved output:\n\n```json\n{\n  \"result\": {\n    \"baseline\": \"\u003Cb>baseline\u003C/b>\",\n    \"duringPolicy\": \"\u003Cimg src=x onerror=alert(\\\"TT_POLICY_SURVIVED_CLEARCONFIG\\\")>\",\n    \"afterClearString\": \"\u003Cimg src=\\\"x\\\">\",\n    \"afterClearTrustedType\": \"[object TrustedHTML]\",\n    \"afterClearTrusted\": \"\u003Cimg src=x onerror=alert(\\\"TT_POLICY_SURVIVED_CLEARCONFIG\\\")>\",\n    \"afterNullTrusted\": \"\u003Cimg src=x onerror=alert(\\\"TT_POLICY_SURVIVED_CLEARCONFIG\\\")>\",\n    \"mountedHTML\": \"\u003Cimg src=\\\"x\\\" onerror=\\\"alert(&quot;TT_POLICY_SURVIVED_CLEARCONFIG&quot;)\\\">\"\n  },\n  \"dialogs\": [\n    \"TT_POLICY_SURVIVED_CLEARCONFIG\"\n  ]\n}\n```\n\nThe important part is the split behavior after cleanup:\n\n- `purify.clearConfig(); purify.sanitize(...);` returns a normal sanitized string (`\u003Cimg src=\"x\">`), because the later call is not asking for a Trusted Type.\n- `purify.clearConfig(); purify.sanitize(..., { RETURN_TRUSTED_TYPE: true });` still uses the old policy and returns attacker-controlled `TrustedHTML`.\n- Passing `{ TRUSTED_TYPES_POLICY: null, RETURN_TRUSTED_TYPE: true }` also still returns attacker-controlled `TrustedHTML`.\n\n## Preconditions\n\nThis is a shared-instance state contamination issue. It matters when one DOMPurify instance is reused by multiple integrations, plugins, request handlers, or components with different trust levels, and a cleanup step relies on `clearConfig()` to restore safe defaults.\n\nThis is not a default string-input bypass. An attacker must be able to influence a prior `TRUSTED_TYPES_POLICY` on the reused instance, or a less-trusted integration must have installed an unsafe policy.\n\n## Severity\n\n impact is XSS at a Trusted Types sink in applications that reuse a DOMPurify instance across trust boundaries. Attack complexity is high because exploitation depends on prior policy injection or a less-trusted integration and a later `RETURN_TRUSTED_TYPE` sink.\n\n## Suggested fix\n\nMake `clearConfig()` reset Trusted Types state as part of restoring defaults, or have `_parseConfig()` explicitly clear `trustedTypesPolicy` and `emptyHTML` when `TRUSTED_TYPES_POLICY: null` is supplied.",null,[],[],[],[],[15],{"_key":16},"CVE-2026-65899",[],[19,21],{"_key":20},"CGA-WF82-9WRV-GJCG",{"_key":22},"CGA-93J5-6RFX-X453","2026-06-15T20:12:53Z","2026-06-17T19:59:19.277774356Z",{"cisa_kev":26,"cisa_ransomware":26,"cisa_vendor":9,"epss_severity":9,"epss_score":9,"severity":9,"severity_score":9,"severity_version":9,"severity_source":9,"severity_vector":9,"severity_status":9},false,[28,34],{"url":29,"sources":30,"tags":32},"https://github.com/cure53/DOMPurify/security/advisories/GHSA-vxr8-fq34-vvx9",[31],"osv_npm",[33],"WEB",{"url":35,"sources":36,"tags":37},"https://github.com/cure53/DOMPurify",[31],[38],"PACKAGE",[],[],[42],{"source":31,"cvss_v2_0":9,"cvss_v3_0":9,"cvss_v3_1":9,"cvss_v4_0":43},{"baseScore":44,"baseSeverity":9,"vectorString":45,"impactScore":9,"exploitabilityScore":9},2.1,"CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N",[47],{"ecosystem":48,"name":49,"vendor":48,"product":49,"cpe_part":9,"purl_type":50,"purl_namespace":9,"purl_name":49,"source":9,"versions":51},"Npm","dompurify","npm",[52],{"version":53,"is_range":54,"range_type":55,"version_start":9,"version_start_type":9,"version_end":56,"version_end_type":57,"fixed_in":9},"lt3_4_9",true,"semver","3.4.9","excluding"]