Sep 29, 2026·6 min read·28 visits
Unauthenticated remote attackers can exhaust server disk space and trigger a denial of service (DoS) by initiating and immediately aborting multipart file uploads before multer completes file path resolution.
An uncontrolled resource consumption vulnerability exists in the multer middleware for Node.js (versions 2.2.0 through 2.3.0) when handling aborted multipart uploads using disk storage. Due to an asynchronous race condition in path resolution, files can become permanently orphaned on disk, leading to storage exhaustion and denial of service.
The Node.js middleware multer is widely used to handle multipart/form-data uploads in Express-based applications. When handling file uploads, the middleware relies on storage engines such as diskStorage or memoryStorage to manage stream ingestion. The disk storage engine provides configurable parameters to define destination directories and file naming conventions. These configuration options often execute asynchronously to allow integrations with databases, UUID generators, or filesystem calls.
In versions 2.2.0 through 2.3.0, multer suffers from a state synchronization deficiency that results in uncontrolled resource consumption. When a client initiates a file upload and subsequently aborts the HTTP request, the middleware attempts to clean up active and completed writes. However, if the abort event occurs during the asynchronous name-resolution phase, the cleaning mechanism fails to detect the in-progress write operation.
This vulnerability is classified under CWE-400 (Uncontrolled Resource Consumption) and CWE-459 (Incomplete Cleanup). Unauthenticated remote attackers can abuse this state-tracking failure to consume all available disk space on the host operating system. The resulting storage exhaustion can degrade application performance, disrupt database write operations, and cause a complete system denial of service.
The underlying issue stems from a race condition between the HTTP request termination lifecycle and the file storage engine's lifecycle. When a multipart upload begins, multer tracks files inside two internal arrays: uploadedFiles (completed writes) and pendingFiles (active writes). When using asynchronous filename or destination callbacks, the storage engine takes a non-zero duration to assign a unique file path on the filesystem. During this initial async window, the file object is placed in pendingFiles but does not yet possess a populated path property.
If the client connection is aborted or terminated before the async callbacks resolve, the middleware intercepts the abort event and invokes finishAbort(). This function is responsible for gathering all files that must be removed and calling the appropriate cleanup methods. To identify files currently being written, the cleanup routine filters the pendingFiles list using a check for the path attribute.
// Vulnerable filtering logic in finishAbort
var filesToRemove = uploadedFiles.concat(
pendingFiles.filter(function (f) { return f.path })
);Because the path assignment callback is still pending, f.path resolves to undefined. The filtering logic consequently omits the file from the filesToRemove list. When the asynchronous path resolution eventually completes, the storage engine proceeds to open a write stream and write the payload to the disk. Because the abort cleanup routine has already executed and returned, no further cleanup processes are scheduled, and the late-arriving file is permanently orphaned in the upload directory.
To address this vulnerability, the patch introduced in version 2.4.0 (commit 53337f9713619ef3381ee6b4e541f926dbaac305) establishes explicit state tracking for the abort sequence. The middleware now maintains an abortCleanupDone boolean and an abortRemovedFiles tracking set.
The fix updates lib/make-middleware.js to modify the completion callback inside _handleFile. If the storage engine completes file creation after finishAbort has already completed, the middleware intercepts this state and checks if the file has already been scheduled for deletion.
// Patched logic handling late-completion files
if (abortCleanupDone) {
if (abortRemovedFiles.has(file)) {
appender.removePlaceholder(placeholder)
decrementPendingWrites()
return
}
return storage._removeFile(req, fileInfo, function () {
appender.removePlaceholder(placeholder)
decrementPendingWrites()
})
}This code ensures that if abortCleanupDone is set to true, any file whose storage engine completes writing afterwards is immediately deleted using _removeFile(). This modification completely closes the race condition window. Even if the path is resolved and the write succeeds after the connection terminates, the file is guaranteed to be deleted immediately upon completion.
Exploiting this vulnerability does not require authentication or complex payload generation. An attacker only needs to manipulate the timing of the request abort relative to the server's file storage resolution. The attack is highly effective when the target application uses slow, complex, or database-backed asynchronous operations within the filename or destination hooks.
An attacker begins by preparing a standard multipart/form-data POST request containing a large file attachment. The attacker transmits the request headers and the initial portion of the boundary wrapper. Immediately after transmission of the boundary, the attacker forcefully closes or destroys the TCP socket. This action triggers the aborted event on the HTTP request object.
To maximize the impact, the attacker can execute this sequence concurrently across multiple connections. Because the cleanup routine fails to track the pending files whose paths have not yet been assigned, every connection abort leaves a file on the disk. This systematic bypass of the cleanup routine allows an attacker to exhaust the host filesystem's inode limits or available disk blocks, triggering application crashes or wider host denial of service.
The severity of CVE-2026-88932 is rated as CVSS 5.3 (Medium). While the vulnerability cannot lead to remote code execution or data exposure directly, it presents a substantial risk to service availability. The attack is unauthenticated, requires zero user interaction, and can be executed via simple network tools over standard HTTP ports.
The direct consequence of successful exploitation is uncontrolled disk space consumption. In containerized environments sharing a storage volume with other critical microservices, a disk-full condition can lead to database corruption, logging failures, and broader platform instability. Since the orphaned files are completely untracked by multer and the parent Node.js application, they remain in the temporary folder until manual intervention occurs.
Furthermore, because no exceptions are raised to the Node.js application process during the orphaned write, traditional application-level monitoring tools will not report any runtime errors or warning logs. This silent failure mode makes detection difficult without active monitoring of disk usage and directory sizes.
The primary remediation path is upgrading the multer package to version 2.4.0 or newer. This version implements the stateful tracking mechanism that reliably cleans up files completing post-abort. If an immediate upgrade is not feasible, several defensive strategies should be deployed to reduce exposure.
Implementing strict rate-limiting on upload endpoints can restrict the volume of concurrent requests a single IP can initiate. Additionally, web application firewalls (WAFs) or reverse proxies can be configured to enforce strict connection timeouts and reject abnormally slow or incomplete uploads.
# Example Nginx configuration to restrict client timeouts
client_body_timeout 10s;
client_header_timeout 10s;
keepalive_timeout 15s;
send_timeout 10s;For deployments utilizing temporary storage directories, administrators should configure automated system tasks to regularly prune files that have been inactive for more than a defined threshold. If the application handles smaller uploads, switching to memory storage (memoryStorage) entirely eliminates disk writes, although this shifts the resource exposure to RAM and requires strict file size boundary configuration.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
multer ExpressJS | >= 2.2.0, <= 2.3.0 | 2.4.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400, CWE-459 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 5.3 (Medium) |
| EPSS Score | 0.00532 |
| Impact | Denial of Service via Disk Storage Exhaustion |
| Exploit Status | No public weaponized exploits available |
| CISA KEV Status | Not Listed |
The software does not properly control the allocation and maintenance of a limited resource, enabling an actor to exhaust that resource.
CVE-2026-126072 (GHSA-rwvh-fw6r-pwvp) is a concurrency deadlock vulnerability in the Ruby on Rails Action Pack framework affecting applications that utilize ActionController::Live response streaming. The defect occurs due to improper synchronization within ActionController::Live::Buffer when handling full bounded queues during stream closure and connection abortion. An unauthenticated remote attacker can trigger this condition by stalling TCP socket reads on streaming endpoints—including Active Storage proxy mode—resulting in permanent worker thread exhaustion and application-wide denial of service.
CVE-2026-126192 is an algorithmic complexity vulnerability in Soup Sieve (soupsieve), the default CSS selector engine for Beautiful Soup 4 in Python. Evaluating a CSS selector that contains a general sibling combinator (~) nested inside a :has() relational pseudo-class against attacker-controlled HTML markup triggers O(n^2) quadratic evaluation complexity when the right-hand sibling target is absent. An unauthenticated attacker can supply small HTML documents containing thousands of sibling elements to exhaust CPU resources and stall application worker threads.
CVE-2026-126190 (GHSA-mmhr-3c5m-f64f) is an inefficient algorithmic complexity vulnerability (CWE-407) in Soup Sieve, the default CSS selector library integrated into Beautiful Soup 4. In versions prior to 4.0, evaluating CSS selectors that contain descendant combinators (whitespace between compound selectors) executes an unmemoized upward traversal of the document tree. When evaluated against deeply nested HTML or XML documents, the time complexity scales polynomially at O(n^(k+1)), where n is the tree depth and k is the number of descendant combinators. Remote attackers can supply compact, deeply nested markup (1 KB to 4 KB) to trigger prolonged CPU starvation and denial of service in Python applications.
CVE-2026-122006 is a critical vulnerability in the Ruby on Rails Active Storage framework affecting versions prior to 8.0.5.2 and 8.1.4.1. When an application processes uploaded file attachments using the ImageMagick variant processor (:mini_magick), the framework invokes ImageMagick's metadata analyzer without applying a restrictive security policy. An unauthenticated attacker can upload a crafted file containing directives for unrestricted ImageMagick coders, such as Magick Scripting Language (MSL), resulting in arbitrary server-side file read and write operations. In deployments using the Disk storage service, attackers can exfiltrate sensitive application configuration files, including secret_key_base and master encryption keys, which enables remote code execution via signed payload forgery.
CVE-2026-128065 (also tracked as GHSA-gg5j-6742-v827) is an authorization bypass vulnerability affecting the @grpc/grpc-js-xds library in the Node.js gRPC ecosystem. In versions 1.14.0 and 1.14.1, XdsServer acknowledges Route and VirtualHost resources from an xDS control plane while failing to parse, store, or apply RBACPerRoute override configurations. When experimental RBAC is enabled and a broad top-level ALLOW policy is paired with restrictive VirtualHost or Route overrides, the server evaluates requests strictly against the top-level policy, permitting unauthorized RPC execution.
CVE-2026-126188 (GHSA-3f4q-8x5m-76v8) is an information disclosure vulnerability in the Active Storage component of Ruby on Rails prior to versions 8.0.5.2 and 8.1.4.1. When generating previews or extracting metadata from uploaded media files, Active Storage invokes the external command-line tools ffmpeg and ffprobe without specifying a format whitelist. An attacker who can upload a crafted HTTP Live Streaming (HLS) playlist while declaring a standard video or audio MIME type can cause FFmpeg to engage the HLS demuxer, resolve file:// segment URIs, and disclose visual frames or metadata from local media files readable by the Rails application process.