Mar 5, 2026·5 min read·5 visits
Multer < 2.1.1 is vulnerable to DoS. Attackers can trigger a stack overflow by sending multipart requests with thousands of files/fields, causing the application to crash due to recursive synchronous function calls.
A high-severity Denial of Service (DoS) vulnerability exists in the Multer Node.js middleware (versions prior to 2.1.1). The flaw stems from uncontrolled synchronous recursion during file cleanup and error handling, allowing remote attackers to crash the Node.js process via crafted multipart requests containing excessive fields or files.
Multer is a standard middleware for handling multipart/form-data in Node.js applications, primarily used for file uploads. A critical vulnerability, identified as CVE-2026-3520, affects all versions prior to 2.1.1. The issue is classified as CWE-674 (Uncontrolled Recursion), where specific code paths recursively call themselves synchronously without releasing the execution stack.
In Node.js's single-threaded event loop architecture, the call stack has a finite size (typically determined by V8 limits). When Multer attempts to clean up uploaded files after an error or processes complex error states, it iterates through files or state transitions recursively on the same tick. If the input data requires a recursion depth exceeding the V8 stack limit (approximately 10,000 to 25,000 frames depending on the environment), the process terminates immediately with a RangeError: Maximum call stack size exceeded.
This vulnerability allows unauthenticated remote attackers to crash the server by sending a single HTTP request containing a massive number of form parts or by triggering a race condition in the error handling logic. No special privileges are required.
The vulnerability manifests in two distinct components of the library: the file cleanup mechanism and the error-handling state machine.
1. Synchronous Recursion in File Cleanup
The function removeUploadedFiles in lib/remove-uploaded-files.js is responsible for deleting files from disk or memory when a request is aborted. In vulnerable versions, this function uses a helper handleFile(idx) that iterates through the array of files. Crucially, if the storage engine's removal method is synchronous (or calls its callback immediately), handleFile calls itself (handleFile(idx + 1)) recursively without yielding to the event loop. Processing a request with 25,000+ files creates a call stack 25,000 frames deep, causing a crash.
2. Non-Idempotent Error Handling
The make-middleware.js logic contains a state machine for handling request failures. When an error occurs, the code attempts to destroy the input stream and propagate the error. However, the error handlers were not idempotent. Destroying the stream could trigger secondary error or close events, which would synchronously re-enter the error handling logic. Without a latch to prevent re-entry, this creates an infinite recursion loop within a single tick, exhausting the stack almost instantly.
The remediation addresses the root cause by breaking the synchronous recursion chain and enforcing idempotency in error handlers.
In lib/remove-uploaded-files.js, the maintainers introduced setImmediate to ensure that each recursive call occurs on a new tick of the event loop. This resets the stack depth for each file processed.
// Vulnerable Code (Recursive Synchronous Call)
function handleFile(idx) {
// ... removal logic ...
if (idx < length - 1) {
handleFile(idx + 1) // Stack grows indefinitely
}
}
// Patched Code (Commit 7e66481)
function handleFile(idx) {
// ... removal logic ...
if (idx < length - 1) {
// Schedule next iteration on the next tick
setImmediate(function () {
handleFile(idx + 1)
})
}
}In lib/make-middleware.js, the patch introduces state guards to prevent multiple invocations of the error handler. The fix ensures that once an error is handled, subsequent events from the stream are ignored or handled without re-triggering the full error workflow.
// Patched Logic (Commit e86fa52)
// An 'onFinished' wrapper now tracks the called state
var called = false;
function onFinished(err) {
if (called) return; // Prevent re-entry
called = true;
// ... proceed with error handling and unpipe stream ...
}Exploiting this vulnerability is trivial and requires no authentication. The attacker acts as a standard client uploading data.
Attack Vector 1: The 'Many-Files' Payload
The attacker constructs a multipart/form-data POST request containing a massive number of file fields. The files do not need to contain content; empty files suffice.
limits: { files: 25000 }), Multer attempts to clean up the files already parsed.Attack Vector 2: Stream Error Loops
A more sophisticated attack involves sending a malformed stream that triggers an error while simultaneously closing the socket. This targets the re-entry bug in make-middleware.js, causing the application to loop infinitely in the error handler until the stack overflows.
The impact is strictly limited to Availability, but the severity is High due to the ease of exploitation and the commonality of the target component.
Operational Risk: Multer is one of the most popular file upload middlewares in the ecosystem. Applications that expose upload endpoints to the public internet without strict upstream WAF limiting are immediately vulnerable.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
multer expressjs | < 2.1.1 | 2.1.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-674 |
| CVSS Score | 8.7 (High) |
| Attack Vector | Network |
| Impact | Denial of Service |
| Exploit Status | PoC Available |
| KEV Listed | No |
The software executes a recursive function that does not have a base case or has a base case that is not reached, leading to excessive consumption of the stack.