Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
📦
📦 npm
Not in CISA KEV
HIGH severity

CVE-2026-34601 xmldom

HIGHFix: xmldom/xmldom@2b852e8

CVE-2026-34601 is a high-severity (CVSS 7.5) CWE-91 vulnerability in xmldom. A fix is available for xmldom — see the affected versions and patch details below.

xmldom: XML injection via unsafe CDATA serialization allows attacker-controlled markup insertion

Also known asGHSA-wh4c-j3r5-mjhp
Published
Apr 2, 2026
Updated
Aug 12, 2026
Affected
3 pkgs
Patched
2 / 3
Exploits
None indexed
Exploitation data as of Sep 22, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
  • CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-34601.

EPSS Exploitation Probability

via FIRST.org ↗
0.5%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs40th percentile — riskier than 40% of all scored CVEsHighest risk

EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.

How urgent is this, really

CVE-2026-34601 plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.

Where this sits among everything scored

Of 377,636 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.

Real-World Exposure

3 pkgs affected

How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.

2Kother npm packages depend on this — each one inherits the vulnerability until it's patched upstream
xmldomnpm
1.3Mdownloads / week
@xmldom/xmldomnpm
36.9Mdownloads / week

Description

Summary

@xmldom/xmldom allows attacker-controlled strings containing the CDATA terminator ]]> to be inserted into a CDATASection node. During serialization, XMLSerializer emitted the CDATA content verbatim without rejecting or safely splitting the terminator. As a result, data intended to remain text-only became active XML markup in the serialized output, enabling XML structure injection and downstream business-logic manipulation.

The sequence ]]> is not allowed inside CDATA content and must be rejected or safely handled during serialization. (MDN Web Docs)

Attack surface

Document.createCDATASection(data) is the most direct entry point, but it is not the only one. The WHATWG DOM spec intentionally does not validate ]]> in mutation methods — only createCDATASection carries that guard. The following paths therefore also allow ]]> to enter a CDATASection node and reach the serializer:

  • CharacterData.appendData()
  • CharacterData.replaceData()
  • CharacterData.insertData()
  • Direct assignment to .data
  • Direct assignment to .textContent

(Note: assigning to .nodeValue does not update .data in this implementation — the serializer reads .data directly — so .nodeValue is not an exploitable path.)

Parse path

Parsing XML that contains a CDATA section is not affected. The SAX parser's non-greedy CDSect regex stops at the first ]]>, so parsed CDATA data never contains the terminator.


Impact

If an application uses xmldom to generate "trusted" XML documents that embed untrusted user input inside CDATA (a common pattern in exports, feeds, SOAP/XML integrations, etc.), an attacker can inject additional XML elements/attributes into the generated document.

This can lead to:

  • Integrity violation of generated XML documents.
  • Business-logic injection in downstream consumers (e.g., injecting <approved>true</approved>, <role>admin</role>, workflow flags, or other security-relevant elements).
  • Unexpected privilege/workflow decisions if downstream logic assumes injected nodes cannot appear.

This issue does not require malformed parsers or browser behavior; it is caused by serialization producing attacker-influenced XML markup.


Root Cause (with file + line numbers)

File: lib/dom.js

1. No validation in createCDATASection

createCDATASection: function (data) accepts any string and appends it directly.

  • Lines 2216–2221 (0.9.8)

2. Unsafe CDATA serialization

Serializer prints CDATA sections as:

<![CDATA[ + node.data + ]]>

without handling ]]> in the data.

  • Lines 2919–2920 (0.9.8)

Because CDATA content is emitted verbatim, an embedded ]]> closes the CDATA section early and the remainder of the attacker-controlled payload is interpreted as markup in the serialized XML.


Proof of Concept — Fix A: createCDATASection now throws

On patched versions, passing ]]> directly to createCDATASection throws InvalidCharacterError instead of silently accepting the payload:

const { DOMImplementation } = require('./lib');

const doc = new DOMImplementation().createDocument(null, 'root', null);
try {
  doc.createCDATASection('SAFE]]><injected attr="pwn"/>');
  console.log('VULNERABLE — no error thrown');
} catch (e) {
  console.log('FIXED — threw:', e.name); // InvalidCharacterError
}

Expected output on patched versions:

FIXED — threw: InvalidCharacterError

Proof of Concept — Fix B: mutation vector now safe

On patched versions, injecting ]]> via a mutation method (appendData, replaceData, .data =, .textContent =) no longer produces injectable output. The serializer splits the terminator so the result round-trips as safe text:

const { DOMImplementation, XMLSerializer } = require('./lib');
const { DOMParser } = require('./lib');

const doc = new DOMImplementation().createDocument(null, 'root', null);

// Start with safe data, then mutate to include the terminator
const cdata = doc.createCDATASection('safe');
doc.documentElement.appendChild(cdata);
cdata.appendData(']]><injected attr="pwn"/><more>TEXT</more><![CDATA[');

const out = new XMLSerializer().serializeToString(doc);
console.log('Serialized:', out);

const reparsed = new DOMParser().parseFromString(out, 'text/xml');
const injected = reparsed.getElementsByTagName('injected').length > 0;
console.log('Injected element found in reparsed doc:', injected);
// VULNERABLE: true  |  FIXED: false

Expected output on patched versions:

Serialized: <root><![CDATA[safe]]]]><![CDATA[><injected attr="pwn"/><more>TEXT</more><![CDATA[]]></root>
Injected element found in reparsed doc: false

Fix Applied

Both mitigations were implemented:

Option A — Strict/spec-aligned: reject ]]> in createCDATASection()

Document.createCDATASection(data) now throws InvalidCharacterError (per the WHATWG DOM spec) when data contains ]]>. This closes the direct entry point.

Code that previously passed a string containing ]]> to createCDATASection and relied on the silent/unsafe behaviour will now receive InvalidCharacterError. Use a mutation method such as appendData if you intentionally need ]]> in a CDATASection node's data (the serializer split in Option B will keep the output safe).

Option B — Defensive serialization: split the terminator during serialization

XMLSerializer now replaces every occurrence of ]]> in CDATA section data with the split sequence ]]]]><![CDATA[> before emitting. This closes all mutation-vector paths that Option A alone cannot guard, and means the serialized output is always well-formed XML regardless of how ]]> entered the node.

Update — 2026-04-xx (0.9.10 / 0.8.13)

splitCDATASections is deprecated

The CDATA split behavior introduced as Option B of this fix (replacing ]]> with]]]]><![CDATA[> during serialization) is deprecated as of 0.9.10 / 0.8.13.

This release introduces a requireWellFormed option on XMLSerializer.serializeToString(). When { requireWellFormed: true } is passed as the second argument, the serializer throws InvalidStateError if CDATA section data contains ]]> — this is the spec-aligned behavior (W3C DOM Parsing and Serialization, require well-formed flag) and the recommended migration path going forward. The split behavior is now controlled by an explicit splitCDATASections option (default true, preserving the current behavior). The three serialization behaviors are: | requireWellFormed | splitCDATASections | Behavior ||---|---|---|| false (default) | true (default) | Split ]]>]]]]><![CDATA[> (current behavior, deprecated) || true | — (ignored) | Throw InvalidStateError — spec-aligned, recommended |\ false | false | Emit verbatim — same as pre-0.9.9 behavior |

requireWellFormed: true takes precedence: the split path is unreachable when it is set.

Migration

Replace any reliance on the default split behavior with an explicit opt-in:


// After (explicit guard, spec-aligned): const xml = new XMLSerializer().serializeToString(doc, { requireWellFormed: true }); // Throws InvalidStateError if any CDATASection contains ']]>' ```

### Removal timeline
Both the `splitCDATASections` option and the underlying `]]>` → `]]]]><![CDATA[>` split mechanics will be removed in the next breaking (`0.10.0`) release. After removal, the only behaviors will be verbatim (default) and `requireWellFormed: true` (throws).

Removal is tracked in [xmldom/xmldom#999](https://github.com/xmldom/xmldom/issues/999).

Affected Packages

3 total 2 fixed
EcosystemPackageVulnerable rangeFix
📦npmxmldomall versionsNo fix
📦npm@xmldom/xmldomall versions0.8.12npm install @xmldom/xmldom@0.8.12
📦npm@xmldom/xmldom0.9.0&&< 0.9.90.9.9npm install @xmldom/xmldom@0.9.9

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for xmldom, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    No patched version of xmldom has shipped for CVE-2026-34601 yet. Where your build allows, override or pin the dependency away from the vulnerable range, and apply any maintainer-recommended mitigation.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like CVE-2026-34601 can be triaged on real exposure rather than presence alone.

Tailored to CVE-2026-34601. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

## Summary `@xmldom/xmldom` allows attacker-controlled strings containing the CDATA terminator `]]>` to be inserted into a `CDATASection` node. During serialization, `XMLSerializer` emitted the CDATA content verbatim without rejecting or safely splitting the terminator. As a result, data intended to remain text-only became **active XML markup** in the serialized output, enabling XML structure injection and downstream business-logic manipulation. The sequence `]]>` is not allowed inside CDATA content and must be rejected or safely handled during serialization. ([MDN Web Docs](https://develope
O3 Security · Impact-Aware SCA

Is CVE-2026-34601 in your dependencies?

O3 Security finds CVE-2026-34601 across npm dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.

CVE-2026-34601: xmldom (High 7.5) | O3 Security