GitHub Advisoryadvisory · npm

GHSA-x4fp-j954-r2f4 xmldom: End-tag Whitespace-Trim Regex ReDoS — quadratic backtracking in the 0.8.x end-tag parser

HIGH Published 2026-09-08 Modified 2026-09-08 Official page ↗
Aliases
CVE-2026-83619
Ecosystem
npm
Packages
@xmldom/xmldom
Severity
High
CVSS vector
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
Weaknesses
CWE-1333, CWE-400
Reviewed
2026-09-08

Affected packages

• npm @xmldom/xmldom: >= 0.7.0, < 0.8.15 → fixed in 0.8.15

Description

Summary On the `@xmldom/xmldom` `0.8.x` line, parsing an XML end tag whose name is followed by a long run of whitespace and then a non-whitespace character triggers quadratic-time regular-expression backtracking (ReDoS), so a single small crafted end tag stalls the Node.js event loop. It is reachable from `DOMParser.parseFromString` under default options, unauthenticated, before any validity check — an availability-only denial of service. The `0.9.x` line is not affected. Details `lib/sax.js` (release-0.8.x, commit `e5c1480`) trims trailing whitespace from a captured end-tag name with an unanchored global regex: • `lib/sax.js` line 120: https://github.com/xmldom/xmldom/blob/e5c14802592685bb872c042c54c3f73758875c85/lib/sax.js#L120 ```js /[ \t\n\r]+$/g ``` Applied to a string shaped `whitespace-run + one non-whitespace char` (e.g. the content of an end tag ``), the engine must, for every starting position, extend `[ws]+` to the end and then fail the `$` anchor when the trailing non-whitespace char is present — classic O(n²) backtracking in the length of the whitespace run. The trimmed substring is delimited only by `indexOf('>')`, so the attacker controls its length directly. Proof of Concept ```js const { DOMParser } = require('@xmldom/xmldom'); // 0.8.x const n = 64 * 1024; const payload = ''; console.time('parse'); new DOMParser().parseFromString(payload, 'text/xml'); console.timeEnd('parse'); ``` Measured (Node 18) — time quadruples per doubling of the whitespace run (canonical O(n²)): | Whitespace run | Isolated regex | End-to-end `parseFromString` (0.8.13) | |---|---|---| | 4 KB | 5.6 ms | 5.7 ms | | 8 KB | 22.7 ms | 22.5 ms | | 16 KB | 88.6 ms | 92 ms | | 32 KB | 354 ms | 361 ms | | 64 KB | 1434 ms | 1452 ms | | 128 KB | 5761 ms | — | Impact Availability only: a single parse of a small crafted document blocks the Node.js event loop for the duration of the quadratic scan (≈1.4 s at 64 KB; multi-second with larger inputs). No memory blow-up, no data exposure, no integrity impact. Because XML is routinely accepted from untrusted sources and parsed with default options, one request can stall a server. Affected Versions Affected on the `0.7.x` and `0.8.x` lines (the trailing-whitespace trim was added in `0.7.0`, present through `0.8.14`); the fix targets the `0.8.x` LTS patch. The `0.9.x` line rewrote end-tag parsing to an anchored linear matcher and never had this regex, so it is not affected. No published unscoped `xmldom` is affected — the vulnerable code exists only in a `0.7.0` git tag that was never released to npm (`npm view xmldom` → `latest` = 0.6.0). Fix Applied Anchors the end-tag trailing-whitespace trim so it runs in linear time instead of backtracking quadratically on a long whitespace run. Byte-identical output. Non-breaking; 0.8.x-only. Severity note The complexity is quadratic, not exponential, so a multi-second stall requires tens-to-hundreds of KB of input. `VA:H` reflects that xmldom applies no input-size limit and the path runs on default-options parsing, so a single unbounded parse can fully stall the event loop.

Related

Alias · CVE (1)

  • CVE-2026-83619 xmldom is a pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module. vulnerability

Weakness · CWE (2)

  • CWE-1333 Inefficient Regular Expression Complexity weakness
  • CWE-400 Uncontrolled Resource Consumption weakness

References