CVE-2026-83607: @xmldom/xmldom Element Name Injection via createElement()
Passing any string to createElement() in @xmldom/xmldom lets an attacker inject arbitrary attributes and event handlers into serialized XML or HTML output, bypassing the requireWellFormed: true…

The problem
Document.createElement() accepted any string as tagName and stored it on the element node with zero validation. The serializer then emitted that name verbatim inside angle brackets.
Critically, the requireWellFormed: true serializer option, which was the recommended mitigation for several prior xmldom CVEs, also did no element-name validation. An attacker who controls the tag name string can break out of the element name and inject arbitrary HTML attributes, including event handlers like onerror.
Proof of concept
A working proof-of-concept for CVE-2026-83607 in @xmldom/xmldom, with the exact payload below.
const { DOMImplementation, XMLSerializer } = require('@xmldom/xmldom');
const doc = new DOMImplementation().createDocument(null, 'root', null);
// Tag name contains injected attributes with an XSS payload
const el = doc.createElement('img src=x onerror="alert(1)"');
doc.documentElement.appendChild(el);
// requireWellFormed: true does NOT block injection in affected versions
const out = new XMLSerializer().serializeToString(doc, { requireWellFormed: true });
console.log(out);
// Output: <root><img src=x onerror="alert(1)"/></root>
// A browser parsing this as HTML executes alert(1).The serializer builds start tags as <${tagName} ...> with no QName check on the element name. Spaces and equals signs in the tagName string are treated as attribute syntax by any downstream HTML parser, so the injected payload lands as real attributes.
The requireWellFormed: true code path only validated text content and comment data in affected versions. It had no guard on element or attribute names. The patch (PR #1043, commit cba1321) adds a QName regex check against the serialized element name inside the requireWellFormed branch and throws InvalidStateError before the start tag is emitted.
Root cause is CWE-91 (XML Injection): untrusted input reaches an output serializer without validation.
The fix
Upgrade to @xmldom/xmldom 0.9.11 (or 0.8.14 on the 0.8.x line). After upgrading, call serializeToString() with { requireWellFormed: true } on every call site that handles untrusted DOM content. Without that option the serializer still emits names verbatim (matching W3C spec default behavior), so auditing all serializeToString() call sites is required.
Creation-time validation in createElement() is deferred to the next breaking release.
Reported by @bhaswanthc, @jmestwa-coder.
Related research
- highCVE-2026-83605CVE-2026-83605: @xmldom/xmldom Attribute Name Injection via setAttribute()
- highCVE-2026-83616CVE-2026-83616: @xmldom/xmldom Processing Instruction Target Injection
- highCVE-2026-83618CVE-2026-83618: @xmldom/xmldom requireWellFormed DocType Injection Bypass via Embedded Line Terminator
- highCVE-2026-83609CVE-2026-83609: @xmldom/xmldom XML Injection via Line Terminator in QName Validation