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 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 Unsandboxed iframe Content Injection happens in JavaScript and how to fix it

A critical vulnerability in `app-viewer/js/LupineVault.js` allowed attacker-controlled HTML fetched from an external CDN to execute scripts in the application's full origin context by injecting it directly into an iframe's `srcdoc` attribute without any sandbox restrictions. The fix adds a `sandbox` attribute to the iframe element, restricting what the injected content can do even if it contains malicious scripts. This prevents cross-site scripting and origin-context script execution that could

critical

How Unsanitized External Content Injection happens in JavaScript and how to fix it

A critical content injection vulnerability in `app-viewer/js/youtube.js` allowed arbitrary HTML and JavaScript from a compromised external CDN to execute directly in the hosting origin's context. The fix replaces unsafe `fetch()`-then-inject patterns with direct URL assignment, eliminating the attack surface entirely. This change prevents supply-chain-style attacks where a compromised JSON manifest could deliver malicious payloads to every user of the viewer.

critical

How Unsafe Attribute Injection happens in JavaScript i18n and how to fix it

A critical attribute injection vulnerability in `assets/js/language.js` allowed attackers with write access to locale JSON files to inject arbitrary HTML attributes — including event handlers like `onclick` — into DOM elements via the `applyTranslations()` function. The fix introduces a strict allowlist (`SAFE_ATTRS`) that restricts which attributes the i18n system can set, closing the injection path entirely. This is a concrete reminder that any code path that writes attacker-influenced data in

critical

How DOM-Based XSS Happens in JavaScript CSS Selectors and How to Fix It

A DOM-based XSS vulnerability in SaltGUI's `Output.js` allowed attackers to inject malicious characters into CSS query selectors by manipulating minion ID values. The root cause was that `btoa()`-encoded IDs could still contain `+`, `/`, and `=` characters that are invalid in CSS selectors, enabling selector breakout. The fix converts the encoding to base64url (RFC 4648 §5), replacing all problematic characters before the ID is used in `querySelector` calls.

critical

How a vulnerable websocket-driver dependency happens in Node.js lockfiles and how to fix it

A Trivy scan flagged `websocket-driver@0.7.4` in this repository's `bun.lock` as affected by CVE-2026-54466, a critical issue in a WebSocket protocol handler that parses untrusted HTTP upgrade requests and frame data. The fix upgrades the package to `0.7.5` and adds an explicit `websocket-driver` entry to the lockfile's override block so every transitive consumer — webpack-dev-server, sockjs, faye-websocket — resolves to the patched build instead of the pinned vulnerable one.