Wysoka

xmldom: Quadratic-memory consumption

  • Ujawniono: 08.09.2026
  • Aktualizacja: 11.10.2026 10:22

Summary

When an element declares a namespace prefix, xmldom copies the entire in-scope namespace map into a fresh object and keeps that copy on the element while it is open on the parse stack. A crafted document that nests N elements, each declaring one unique prefix, therefore drives the parser to hold on the order of N(N+1)/2 = O(N²) namespace-map entries at its peak, so a small, highly compressible input exhausts the heap. Parsing runs under default options on untrusted, network-delivered XML, so a sub-megabyte payload can OOM-crash the process before any application-level validation runs — an unauthenticated denial of service.

Details

appendElement performs the copy: _copy clones the current namespace map into a fresh object for each prefix-declaring element, and the copy is retained on that element's parse-stack entry:

js
if (localNSMap == null) {
    localNSMap = Object.create(null);
    _copy(currentNSMap, (currentNSMap = Object.create(null)));   // full copy of all ancestor prefixes
}
currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
...
el.currentNSMap = currentNSMap;   // retained while the element is open on the parse stack

https://github.com/xmldom/xmldom/blob/08a22d78e4bc50f12ce9f5090b8d96ee6031ac7b/lib/sax.js#L467-L540

The copies stack: the element at depth i copies a map of size ~i, and every ancestor stays live on the parse stack until it closes, so at the deepest point Σi namespace entries are held at once. That peak is transient — the completed DOM retains only O(N), one small namespace map per node — but it is reached during parsing, which is what OOM-crashes the process.

Proof of Concept

A minimal document — N nested elements, each declaring one unique namespace prefix (no SAML wrapper needed):

js
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>`;   // <r><a xmlns:p0="urn:0">...<a xmlns:p{n-1}="urn:{n-1}">...</a>...</r>
}

for (const n of [2000, 4000, 8000, 16000]) {
  const src = build(n);
  new DOMParser().parseFromString(src, 'text/xml');   // peak memory ~ O(n^2)
  console.log(n, (src.length / 1024).toFixed(0) + ' KB in', (process.resourceUsage().maxRSS / 1024).toFixed(0) + ' MB peak RSS');
}

Measured on Node.js v24 (peak RSS ~quadruples per doubling of depth; absolute numbers vary by host):

depth input peak RSS
2,000 56 KB 266 MB
4,000 115 KB 622 MB
8,000 232 KB 1.9 GB
16,000 ~470 KB OOM crash (default ~4 GB heap)

About 470 KB of trivially-generated, highly-compressible input crashes a default Node.js process; larger depths scale as O(N²) into the tens of GB, crashing larger hosts (as first measured by the reporter with a SAML-shaped payload).

Impact

Unauthenticated denial of service against any service that parses attacker-influenced XML with xmldom under default options. A single sub-megabyte request drives multi-gigabyte peak memory and can OOM-crash the process before any application-level validation (e.g. schema checks or a SAML signature verification) runs. The payload is a plain namespace-nesting document and highly compressible, so it is effective over compressed transports (e.g. an HTTP-Redirect / DEFLATE binding, not only POST bindings).

Severity note

The CVSS 4.0 vector scores availability only (VC:N/VI:N/VA:H): the flaw neither discloses nor alters data, it exhausts the heap. VA:H is justified because a single unauthenticated, network-delivered request (AV:N/PR:N/UI:N) of trivial complexity (AC:L/AT:N) drives the parser to multi-gigabyte peak memory and OOM-crashes the process before any application-level logic runs — a full loss of availability for the affected service.

Fix Applied

Inherit each element's in-scope namespace map through the prototype chain instead of copying it for every prefix-declaring element, so a deeply namespaced document holds O(N) namespace entries instead of O(N²) at peak. Behavior-preserving: serialized output is byte-identical, only the memory cost drops. Non-breaking and independent of requireWellFormed; ships on both maintained versions.

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Paczka npm xmldom >= 0.1.5, <= 0.6.0 brak poprawki
Paczka npm @xmldom/xmldom >= 0.7.0, < 0.8.15, >= 0.9.0, < 0.9.12 0.8.15, 0.9.12

Odnośniki

Ocena CVSS -
Wektor CVSS
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Słabość (CWE)
CWE-770
Platforma
npm
Paczka
xmldom, @xmldom/xmldom
Ujawniono
08.09.2026
Aktualizacja
11.10.2026 10:22

Źródła i licencje

OSV / GitHub Advisory Database - GHSA-965w-775f-mr7g - CC BY 4.0

Historia podatności: xmldom

Wszystkie opisane podatności tej paczki (Paczka npm), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (17) w archiwum
Wszystkich wpisów
17
Pierwsza → ostatnia
03.2021 09.2026
Bez poprawki
16
Wykorzystywana w atakach
0

Rozkład istotności

  • Krytyczna 1
  • Wysoka 12
  • Średnia 4

Ujawnienia w latach

  1. 2021: 2
  2. 2022: 1
  3. 2023: 0
  4. 2024: 0
  5. 2025: 0
  6. 2026: 14
Istotność:
  1. Wysoka CVE-2026-83608 <= 0.6.0 brak poprawki
  2. Wysoka CVE-2026-83613 <= 0.6.0 brak poprawki
  3. xmldom: Quadratic-memory consumption ten wpis
    Wysoka CVE-2026-83615 >= 0.1.5, <= 0.6.0 brak poprawki
  4. Wysoka CVE-2026-41673 <= 0.6.0 brak poprawki
  5. Krytyczna · 9.8 CVE-2022-39353 <= 0.6.0 brak poprawki

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.