CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-3520
8.7

CVE-2026-3520: Denial of Service via Uncontrolled Recursion in Multer

Alon Barad
Alon Barad
Software Engineer

Mar 5, 2026·5 min read·5 visits

PoC Available

Executive Summary (TL;DR)

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.

Vulnerability Overview

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.

Root Cause Analysis

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.

Code Analysis & Patch

The remediation addresses the root cause by breaking the synchronous recursion chain and enforcing idempotency in error handlers.

Fix 1: Asynchronous Cleanup Iteration

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)
    })
  }
}

Fix 2: Idempotent Error State

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 ...
}

Exploitation Methodology

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.

  1. Preparation: Generate a request body with ~25,000 boundaries defining distinct file parts.
  2. Trigger: Send the request. If the server is configured to accept this number of files, Multer processes them. If a limit is hit (e.g., limits: { files: 25000 }), Multer attempts to clean up the files already parsed.
  3. Crash: The cleanup routine recurses synchronously for every file, hitting the stack limit and crashing the process.

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.

Impact Assessment

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.

  • Availability (High): A single malicious request can terminate the Node.js process. In environments without robust process managers (like PM2 or Kubernetes with restart policies), this leads to prolonged downtime. Even with auto-restart, a sustained flood of these requests creates a denial-of-service loop.
  • Confidentiality (None): The vulnerability does not allow memory reading or data exfiltration.
  • Integrity (None): The vulnerability does not allow code execution or data modification.

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.

Official Patches

expressjsFix for recursive file cleanup
expressjsFix for error handling state machine

Fix Analysis (2)

Technical Appendix

CVSS Score
8.7/ 10
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

Affected Systems

Node.js applications using expressjs/multer

Affected Versions Detail

Product
Affected Versions
Fixed Version
multer
expressjs
< 2.1.12.1.1
AttributeDetail
CWE IDCWE-674
CVSS Score8.7 (High)
Attack VectorNetwork
ImpactDenial of Service
Exploit StatusPoC Available
KEV ListedNo

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.003Application or System Exploitation
Impact
CWE-674
Uncontrolled Recursion

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.

Known Exploits & Detection

GitHub AdvisoryOfficial advisory containing reproduction steps and PoC logic.

Vulnerability Timeline

Fixes committed to main branch
2026-03-01
Version 2.1.1 released
2026-03-04
Public disclosure (GHSA & CVE)
2026-03-04

References & Sources

  • [1]GHSA-5528-5vmv-3xc2
  • [2]CWE-674: Uncontrolled Recursion
  • [3]CVE-2026-3520 Record

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.