GHSA-474x-hrwr-fgx4: fast-xml-parser: Quadratic CPU consumption scanning unterminated stop-node tags
Summary
With the non-default stopNodes option, a stop node's body with many "<a " fragments and no closing ">" anywhere after makes readStopNodeData() rescan the entire remaining input from every "<". The failed lookahead is neither cached nor bounded, so n fragments cost O(n²) before the parser throws. Availability-only (CPU exhaustion), needs the non-default stopNodes option — not benchmarked yet, see Proof of Concept.
Details
CWE-407 — Inefficient Algorithmic Complexity
Code - OrderedObjParser.js:520 — parseXml() calls readStopNodeData() after a matching stop node opens - OrderedObjParser.js:810 — calls readTagExp() for every non-special < - OrderedObjParser.js:688-722 — tagExpWithClosingIndex() scans to end-of-input and returns undefined when no > exists - OrderedObjParser.js:812-818 — on failure, i isn't advanced, so the next < repeats the same full scan - OrderedObjParser.js:423 — the main parse loop throws immediately on the same failure; only the stop-node path retries
Root cause: a failed closing-> lookahead is neither cached nor bounded — n copies of <a with no later > means n scans over the remaining input, O(n²) work, before it finally throws.
Fix 1. Throw immediately in readStopNodeData() when readTagExp() returns undefined 2. Or break the loop on the first failed scan 3. Or find the next > once and reuse/bound that result 4. Add a test asserting near-linear scaling when payload size doubles
Proof of concept
Not benchmarked — static-analysis finding, confidence 0.5.
To confirm: configure stopNodes matching a root element. Build input as '<stop>' + '<a '.repeat(n). Time parse() until it throws Unexpected end of <tag>. Start around n=10,000 and double it — quadratic should show ~4x time per doubling, linear ~2x. Control: same input with a > present, or stopNodes unset.
Impact
CPU-exhaustion DoS in Node.js services parsing untrusted XML with stopNodes enabled. A ~100KB payload is estimated at ~10⁹ character operations (roughly a second or more of blocked event loop) — analytical estimate, not a benchmark. No confidentiality/integrity impact. CVSS 3.1: AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L (3.7, Low).
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
npm/fast-xml-parserto a version that resolves this vulnerability.Fixed in 5.12.0 - Configuration
Unset or disable the non-default stopNodes option when parsing untrusted XML to avoid quadratic CPU consumption from unterminated stop-node tags.
fast-xml-parser stopNodes = unset
Event History
Frequently Asked Questions
Are deployments using the default parser configuration exposed?
The issue requires the non-default stopNodes option. Deployments that do not enable stopNodes are not affected by this specific retry behavior.
What input conditions are needed to trigger the excessive CPU use?
An attacker needs to supply input processed with stopNodes that contains a matching stop node whose body has many "<a " fragments and no closing ">" later in the input. No privileges or user interaction are required.
What can be done if an update cannot be applied immediately?
Avoid enabling or using the stopNodes option where possible. The inefficient repeated scan occurs only in the stop-node parsing path; the main parse loop throws immediately on the same failed lookahead.