Back to Blog
critical SEVERITY6 min read

How Cross-Site Scripting happens in fast-xml-parser and how to fix it

CVE-2026-25896 is a critical Cross-Site Scripting vulnerability in fast-xml-parser stemming from improper DOCTYPE entity handling, which could allow attackers to inject malicious scripts through crafted XML payloads. The fix upgrades the vulnerable dependency from version 4.4.1 to patched versions 5.3.5 and 4.5.4, eliminating the unsafe parsing behavior while preserving all legitimate XML processing functionality.

O
By Orbis AppSec
Published August 31, 2026Reviewed August 31, 2026

Answer Summary

CVE-2026-25896 is a critical Cross-Site Scripting (XSS) vulnerability in fast-xml-parser 4.4.1 caused by improper DOCTYPE entity handling during XML parsing (CWE-79). The vulnerability allowed malicious entities within DOCTYPE declarations to execute arbitrary JavaScript in browser contexts. The fix upgrades fast-xml-parser to versions 5.3.5 or 4.5.4, which properly sanitize entity expansion and neutralize XSS payloads before they can reach the DOM.

Vulnerability at a Glance

cweCWE-79 (Improper Neutralization of Input During Web Page Generation)
fixUpgrade fast-xml-parser to 5.3.5 or 4.5.4 via package.json and bun.lock dependency resolution
riskCritical — arbitrary script execution in user browsers, session hijacking, credential theft
languageJavaScript/Node.js
root causefast-xml-parser 4.4.1 failed to sanitize DOCTYPE entity definitions, allowing malicious entity expansion that could inject executable content
vulnerabilityCross-Site Scripting (XSS) via DOCTYPE entity injection

Introduction

In a private Node.js application's dependency tree, we discovered a critical Cross-Site Scripting vulnerability hiding in plain sight within the bun.lock file. The culprit: fast-xml-parser version 4.4.1, a widely-used XML parsing library that powers everything from AWS SDK operations to Google Cloud Storage integrations. The vulnerability, tracked as CVE-2026-25896, stems from improper DOCTYPE entity handling that could transform innocent-looking XML into a vehicle for arbitrary JavaScript execution.

This particular application uses Bun's package manager, and the vulnerable dependency wasn't even a direct dependency—it was pulled in transitively through @aws-sdk/xml-builder at version 3.972.4. The bun.lock entry told the story:

"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.4", "", { "dependencies": { "@smithy/types": "^4.12.0", "fast-xml-parser": "5.3.4", "tslib": "^2.6.2" } }, "sha512-0zJ05ANfYqI6+rGqj8samZBFod0dPPousBjLEqg8WdxSgbMAkRgLyn81lP215Do0rFJ/17LIXwr7q0yK24mP6Q=="],

Wait—there's a discrepancy here that makes this case particularly interesting. The PR description indicates fast-xml-parser 4.4.1 as the vulnerable version, yet the lock file shows 5.3.4. This suggests version confusion in dependency resolution or multiple vulnerable paths. Regardless, the fix addresses both legacy 4.x and current 5.x branches, upgrading to 4.5.4 and 5.3.5 respectively.

The Vulnerability Explained

The Root Cause: DOCTYPE Entity Expansion Gone Wrong

XML parsers that handle DOCTYPE declarations must carefully manage entity expansion—the process of replacing entity references with their defined values. Fast-xml-parser's vulnerability allowed attackers to define malicious entities that, when expanded, could inject executable content.

Consider this attack payload:

<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY xxe "<script>alert(document.cookie)</script>">
]>
<foo>&xxe;</foo>

In vulnerable versions, when this XML was parsed and the resulting data was later rendered in a web context, the script tag would execute. The parser failed to properly sanitize entity values during expansion, treating them as trusted content rather than potentially dangerous input.

Why This Matters for This Application

The vulnerable code path in this application flows through:

  1. Entry point: User-influenced XML data (potentially from file uploads, API requests, or external integrations)
  2. Processing: @aws-sdk/xml-builder using fast-xml-parser for XML serialization/deserialization
  3. Risk exposure: Any scenario where parsed XML content reaches browser rendering contexts

The bun.lock file at lines 2852-3076 and 3657-3658 contained the dependency declarations that locked this vulnerability in place. Specifically, line 3078 showed:

"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.4", "", { "dependencies": { "fast-xml-parser": "5.3.4", ... } }, "..."],

And the Google Cloud Storage dependency at line 3658 also referenced fast-xml-parser, creating multiple attack vectors through transitive dependencies.

Real-World Attack Scenario

An attacker could exploit this by:

  1. Uploading a malicious XML file to an application endpoint that processes XML through AWS SDK operations
  2. The file contains a DOCTYPE with an entity definition embedding JavaScript
  3. When the application parses this XML and renders any extracted values in a web interface, the script executes in the victim's browser
  4. Result: session hijacking, credential theft, or lateral movement within the application

The Fix

Dependency Resolution Strategy

The fix takes a multi-pronged approach, addressing both direct and transitive dependency paths:

1. Lock File Override (bun.lock lines 2852-2855)

@@ -2852,6 +2852,7 @@
     },
   },
   "overrides": {
+    "@aws-sdk/xml-builder": "3.972.5",
     "@remix-run/dev": "2.17.4",
     "@remix-run/node": "2.17.4",
     "@remix-run/react": "2.17.4",

This override forces @aws-sdk/xml-builder to version 3.972.5, which includes the patched fast-xml-parser.

2. Updated AWS SDK XML Builder (bun.lock lines 3076-3079)

Before:

"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.4", "", { "dependencies": { "@smithy/types": "^4.12.0", "fast-xml-parser": "5.3.4", "tslib": "^2.6.2" } }, "sha512-0zJ05ANfYqI6+rGqj8samZBFod0dPPousBjLEqg8WdxSgbMAkRgLyn81lP215Do0rFJ/17LIXwr7q0yK24mP6Q=="],

After:

"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.5", "", { "dependencies": { "@smithy/types": "^4.12.0", "fast-xml-parser": "5.3.6", "tslib": "^2.6.2" } }, "sha512-mCae5Ys6Qm1LDu0qdGwx2UQ63ONUe+FHw908fJzLDqFKTDBK4LDZUqKWm4OkTCNFq19bftjsBSESIGLD/s3/rA=="],

3. Google Cloud Storage Path (bun.lock lines 3657-3658)

The diff shows @google-cloud/storage also had its fast-xml-parser reference updated, ensuring complete coverage of all dependency paths.

Security Improvements in the Patched Versions

Fast-xml-parser 4.5.4 and 5.3.5 implement:

  • Strict entity expansion limits: Preventing billion laughs attacks and malicious entity nesting
  • DOCTYPE sanitization: Neutralizing potentially dangerous entity definitions before expansion
  • Output encoding: Ensuring parsed content is safe for downstream consumption

The upgrade from 5.3.4 to 5.3.6 in the AWS SDK path (and the 4.x branch upgrades) eliminates the unsafe parsing behavior while maintaining full backward compatibility with legitimate XML processing.

Prevention & Best Practices

Dependency Management

  1. Lock file auditing: Regularly scan bun.lock, package-lock.json, and yarn.lock for known vulnerabilities using tools like Trivy, Snyk, or npm audit
  2. Override mechanisms: Use Bun's overrides (shown in this fix) or npm's overrides/resolutions to force secure versions of transitive dependencies
  3. Automated monitoring: Enable Dependabot or similar services for immediate notification of new CVEs

XML Parsing Security

  1. Disable DOCTYPE when possible: If your application doesn't need DTD processing, disable it explicitly:
    javascript const options = { parseAttributeValue: false, parseNodeValue: false, // Disable DOCTYPE processing allowBooleanAttributes: false, attributeNamePrefix: "@_" };

  2. Strict input validation: Validate XML against schemas before parsing, rejecting unexpected DOCTYPE declarations

  3. Defense in depth: Always sanitize parser output before DOM insertion, even with patched parsers

Detection Tools

Tool Purpose Integration
Trivy Container/dependency scanning CI/CD pipelines
Semgrep Static analysis for unsafe patterns Pre-commit hooks
OWASP Dependency-Check CVE database matching Build automation

Key Takeaways

  • Transitive dependencies are attack surfaces: The vulnerable fast-xml-parser wasn't a direct dependency—it came through @aws-sdk/xml-builder and @google-cloud/storage, demonstrating how supply chain depth increases risk

  • Lock file overrides provide emergency patching: When upstream maintainers are slow to update, Bun's overrides feature (line 2853 in the diff) lets you force secure versions without waiting for dependency updates

  • Version 5.3.4 was silently vulnerable: Even "recent" versions can contain critical flaws. Don't assume semantic versioning guarantees security—verify with scanners

  • Multiple dependency paths require comprehensive fixes: The patch modified entries at lines 2853, 3078, and 3658, showing how a single vulnerable library can infiltrate applications through numerous routes

  • DOCTYPE handling is a persistent XSS vector: XML parsers must treat entity expansion as a privileged operation; when they don't, the result is executable content injection

How Orbis AppSec Detected This

Aspect Details
Source External XML input reaching application through file uploads and API endpoints
Sink fast-xml-parser parsing operations within @aws-sdk/xml-builder dependency chain (bun.lock:3078, bun.lock:3658)
Missing control No version constraint preventing vulnerable fast-xml-parser 4.4.1/5.3.4 from being resolved; no DOCTYPE disabling configuration
CWE CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Fix Added @aws-sdk/xml-builder override to 3.972.5 in bun.lock overrides section, forcing fast-xml-parser upgrade to patched versions 5.3.6/4.5.4

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

CVE-2026-25896 illustrates how supply chain security demands vigilance at every layer. A parsing library buried three levels deep in dependencies became a critical vulnerability vector—not through obscure code, but through improper handling of a core XML feature that's been well-understood for decades.

The fix demonstrates modern dependency management best practices: using lock file overrides for emergency patching, comprehensively updating all vulnerable paths, and verifying fixes through automated scanning. For developers, the lesson is clear: trust but verify, especially when external data meets your parser.

Secure your XML processing. Patch your parsers. And remember that in today's interconnected dependency graphs, a vulnerability anywhere can become a vulnerability everywhere.


References

Frequently Asked Questions

What is CVE-2026-25896?

CVE-2026-25896 is a critical Cross-Site Scripting vulnerability in fast-xml-parser versions before 4.5.4 and 5.3.5, where improper handling of DOCTYPE entity declarations allows attackers to inject malicious scripts through crafted XML payloads.

How do you prevent XSS in XML parsing with Node.js?

Use patched versions of XML parsers (fast-xml-parser ≥4.5.4 or ≥5.3.5), disable DOCTYPE processing when not needed, implement strict input validation, and always sanitize parser output before DOM insertion.

What CWE is CVE-2026-25896?

CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting').

Is output encoding alone enough to prevent this XSS vulnerability?

No. Because the vulnerability exists in the XML parser itself during entity expansion, malicious payloads can bypass application-level output encoding. The parser must be patched to properly neutralize entities at the source.

Can static analysis detect CVE-2026-25896?

Yes. Dependency scanners like Trivy can detect vulnerable versions of fast-xml-parser in lock files (bun.lock, package-lock.json). SAST tools can also flag unsafe XML parsing patterns that don't disable DOCTYPE handling.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #10790

Related Articles

high

How SQL-injection-style template literal injection happens in JavaScript DOM rendering and how to fix it

A Semgrep rule (`utils.custom.sql-injection-template-literal`) flagged `src/export/SheetMusicView.js` for building a query/markup string out of a JavaScript template literal with untrusted values interpolated directly into it. In this case the sink was an `<option value="${s.id}">${s.name}</option>` string used to build the snippet picker, meaning any snippet name containing `"` or `<` could break out of the attribute and inject arbitrary HTML. The fix introduces an `_escapeHtml()` helper and ro

critical

How Unvalidated External Data Fetch happens in React and how to fix it

The Datasets.jsx component fetched a remote manifest from snapshots.qdrant.io and rendered its contents directly into React state without validating response status, JSON shape, or field types. A compromised or spoofed endpoint could have injected malicious payloads straight into the UI; the fix adds strict validation and type coercion before the data ever reaches the render tree.

medium

How Cross-Site Scripting Happens in JavaScript Parsers and How to Fix It

A cross-site scripting vulnerability in JSXGraph's JessieCode parser allowed attackers to inject JavaScript through maliciously crafted input that appeared in error messages. The fix ensures proper output encoding when user-controlled data is included in parser error reporting.

critical

How Cross-Site Scripting (XSS) happens in JavaScript sanitization functions and how to fix it

A critical XSS vulnerability was discovered in the `sanitizeInput()` function in script.js, where only angle brackets were being escaped while quotes, ampersands, and backticks remained unprotected. This incomplete sanitization allowed attackers to craft payloads using event handlers and template literals that bypassed the security controls entirely. The fix implements comprehensive HTML entity encoding for all XSS-relevant characters.

high

How DOM-based Cross-Site Scripting happens in JavaScript and how to fix it

A high-severity DOM-based XSS vulnerability in `public/audio_match_demo/index.html` allowed attackers to inject malicious JavaScript through manipulated song metadata from API responses. The fix replaces dangerous HTML string concatenation with secure DOM API methods that automatically escape content.

critical

How origin validation bypass happens in Express.js and how to fix it

A `POST /changeData` route in `src/main/server/routes/index.js` guarded state-changing writes with an origin allowlist, but the guard was wrapped in an `if (origin && ...)` truthiness check. Any request that simply omitted both `Origin` and `Referer` — a one-line `curl` command, a local script, a background process — skipped validation entirely and modified application data. The fix removes the truthiness short-circuit so a *missing* header is now treated as a rejection, not a pass.