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-77037

CVE-2026-77037: File Descriptor Leak and Denial of Service in Multer Disk Storage

Amit Schendel
Amit Schendel
Senior Security Researcher

Sep 9, 2026·5 min read·68 visits

Executive Summary (TL;DR)

Unauthenticated remote attackers can exhaust server file descriptors by repeatedly initiating and aborting multipart file uploads in multer v2.2.0, causing a complete denial of service.

A resource consumption vulnerability exists in the multer library version 2.2.0 when utilizing the disk storage engine. When a remote client aborts or truncates an in-progress file upload, multer removes the partial file from the disk but fails to properly close the active write stream. This behavior leaves the underlying file descriptor open in the operating system, allowing a remote attacker to systematically exhaust the server's file descriptor limits and trigger a Denial of Service.

Vulnerability Overview

The library multer is an extremely common Node.js middleware designed to handle multipart/form-data uploads. When dealing with file uploads, applications rely on storage engines to persist the incoming data stream to either memory or disk. The default disk storage engine (diskStorage) writes incoming files directly to the host filesystem as they are parsed from the network socket.

This architecture creates a direct channel between untrusted network inputs and host filesystem operations. Because parsing occurs asynchronously, the middleware must handle unexpected interruptions gracefully. If a client terminates the network connection during an upload, the application must immediately release all associated OS resources, including memory allocations and open file handles.

In version 2.2.0, the cleanup logic fails to manage the lifecycle of the write streams properly. This results in an incomplete cleanup flaw classified under CWE-459. By repeatedly interrupting the upload process, an unauthenticated attacker can exhaust the host's file descriptor table, resulting in a persistent Denial of Service.

Technical Root Cause Analysis

The underlying flaw stems from the way Node.js handles stream piping. In multer version 2.2.0, the multipart parser streams the incoming request body directly into a write stream using the standard .pipe() method:

file.stream.pipe(outStream);

In standard Node.js stream architecture, piping transfers data from a readable source to a writable destination. However, if the source stream emits an error, is destroyed, or is abruptly truncated due to a disconnected client, the .pipe() method does not automatically propagate the closure or destruction to the destination write stream. The destination stream remains in an open state, holding its assigned file descriptor.

When a network socket disconnects prematurely, multer registers the failure and attempts to clean up by invoking fs.unlink() on the partial file path. On POSIX-compliant systems like Linux, the fs.unlink() system call removes the directory entry for the file, which makes it disappear from standard listings. However, because the process still holds an open file descriptor pointing to the deleted file, the operating system retains the physical block pointers and keeps the file descriptor active in /proc/self/fd. On Windows, the OS blocks the deletion entirely, throwing EPERM or EBUSY because the file has an active stream lock.

Code-Level Patch Analysis

To resolve the vulnerability, the development team updated the codebase in commit eef74440b491ef0f976f3d25895e8089ae495df0. The key change replaces the manual .pipe() operation with Node.js's native stream.pipeline utility, which manages the entire lifecycle of piped streams.

// Vulnerable Implementation (storage/disk.js)
file.stream.pipe(outStream)
outStream.on('error', cb)
outStream.on('finish', function () {
  cb(null, { ... })
})
// Patched Implementation (storage/disk.js)
pipeline(file.stream, outStream, function (err) {
  if (err) return cb(err)
 
  cb(null, {
    destination: destination,
    filename: filename,
    path: finalPath,
    size: outStream.bytesWritten
  })
})

The stream.pipeline implementation ensures that if either the incoming request stream or the write stream encounters an error or aborts, the utility automatically invokes .destroy() on both streams, closing the file descriptor immediately. The patch also introduces a global WeakMap named openStreams to link file objects to their active write streams, allowing safe deletion only after the stream is fully closed and the descriptor released.

Exploitation Methodology

Exploiting this vulnerability does not require complex payloads or bypassed authentication mechanisms. An attacker only needs network access to an endpoint that uses the multer disk storage engine. The attack vector targets resource consumption limit constraints in the operating system, such as ulimit -n (the limit of open files permitted per process).

An attacker begins the attack by establishing a TCP connection and sending a standard HTTP POST request with Content-Type: multipart/form-data. As the server begins processing the upload and initializes a write stream, the attacker waits a fraction of a second and then sends a TCP RST (Reset) packet or forcefully destroys the client socket. This causes the underlying socket stream to emit an error, terminating the request mid-stream.

Because the destination write stream is never closed by the vulnerable multer code, one file descriptor remains leaked. By scripting a simple concurrent loop to repeat this cycle several hundred times, the attacker can quickly reach the host operating system's default file descriptor limits (typically 1024 on standard Linux distributions). Once exhausted, the Node.js process cannot accept new TCP sockets or perform critical network and filesystem calls, resulting in a persistent Denial of Service.

Remediation and Mitigation Strategies

The primary remediation for this vulnerability is upgrading the application's dependencies to ensure multer version 2.3.0 or later is installed. The package manager command npm install multer@latest will retrieve the patched version, replacing the vulnerable stream handling structure.

If upgrading the library is not immediately possible due to production freeze rules, developers can implement temporary workarounds. One effective method is configuring a reverse proxy such as Nginx or HAProxy in front of the Node.js application. The proxy can enforce strict request timeout policies, buffer request bodies fully before passing them to Node.js, or limit the maximum rate of concurrent connections from single source IPs.

Alternatively, applications can transition from disk storage to memory storage by configuring multer.memoryStorage(). While this prevents the file descriptor leak, developers must exercise caution as memory-backed storage is susceptible to heap memory exhaustion when processing large file uploads. Process monitoring solutions like pm2 or Kubernetes liveness probes can also be configured to automatically restart the container or process if file descriptor consumption surpasses safety limits.

Official Patches

expressjsOfficial patch implementing pipeline safety fixes

Fix Analysis (1)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.35%
Top 72% most exploited

Affected Systems

Node.js applications running multer 2.2.0 configured with diskStorage

Affected Versions Detail

Product
Affected Versions
Fixed Version
multer
expressjs
= 2.2.02.3.0
AttributeDetail
CWE IDCWE-400 (Uncontrolled Resource Consumption) / CWE-459 (Incomplete Cleanup)
Attack VectorNetwork / Unauthenticated
CVSS v3.17.5 (High)
EPSS Score0.00347 (Percentile: 27.68%)
ImpactDenial of Service (DoS) via File Descriptor Exhaustion
Exploit StatusProof of Concept (PoC) available
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
CWE-400
Uncontrolled Resource Consumption

The software does not control the allocation and maintenance of a limited resource, enabling an actor to exhaust that resource.

Known Exploits & Detection

GitHub Test SuiteIntegration test validating file descriptor count in /proc/self/fd during repeated aborted uploads.

References & Sources

  • [1]GitHub Security Advisory GHSA-qfvm-cv95-jqjf
  • [2]OpenJS Foundation Security Portal
  • [3]Multer Version 2.3.0 Release Notes
  • [4]CVE-2026-77037 Record
  • [5]NVD Registry Details

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.

More Reports

•20 minutes ago•CVE-2026-113715
2.0

CVE-2026-113715: Configuration Key Injection via Unicode Line Boundary in virtualenv

In virtualenv versions prior to 21.14.9, creating isolated Python virtual environments using the standard library creator (`--creator venv`) allows configuration key injection into `pyvenv.cfg` if an attacker can control or influence the destination directory path containing Unicode line break characters.

Amit Schendel
Amit Schendel
2 views•5 min read
•about 1 hour ago•CVE-2026-113723
7.1

CVE-2026-113723: OS Command Injection via Unsafe Prompt Expansion in PyPA virtualenv

A command injection vulnerability in PyPA virtualenv prior to version 21.14.9 allows local attackers to execute arbitrary commands when a user sources a generated shell activation script containing a crafted prompt value.

Alon Barad
Alon Barad
2 views•5 min read
•about 2 hours ago•CVE-2026-113720
4.4

CVE-2026-113720: Local Permission Inheritance Vulnerability in virtualenv

virtualenv prior to version 21.14.9 contains a local permission inheritance vulnerability in its app-data copy seeder. Due to the reliance on Python's standard shutil.copy() function, permissions from cached packages are replicated directly onto newly created virtual environment files, ignoring the active process umask and allowing unprivileged local attackers to inject code.

Amit Schendel
Amit Schendel
5 views•5 min read
•about 3 hours ago•CVE-2026-113718
7.1

CVE-2026-113718: Code Injection in pypa/virtualenv XonshActivator via Multibyte Encoding Misalignment

A code injection vulnerability in pypa/virtualenv prior to version 21.14.9 allows arbitrary command execution in xonsh shells using legacy multibyte encodings when sourcing activate.xsh.

Amit Schendel
Amit Schendel
6 views•5 min read
•about 4 hours ago•CVE-2026-113714
2.3

CVE-2026-113714: Cache Poisoning and Unvalidated Wheel Download in virtualenv

Prior to version 21.14.9, virtualenv downloads wheel files directly into its reusable persistent cache directory prior to verifying PyPI digests or compatibility. Combined with unsanitized stdout parsing from pip, a controlled package index can cause virtualenv to calculate digests against pre-existing local files while leaving unverified archives in the shared persistent cache.

Amit Schendel
Amit Schendel
6 views•5 min read
•about 5 hours ago•CVE-2026-113717
2.3

CVE-2026-113717: Package Digest Verification Bypass in virtualenv Pip Seeder

A verification bypass vulnerability in virtualenv allows unverified Python wheel installation when using pip seeding with the download flag. Affected versions fail to perform SHA-256 digest validation against PyPI metadata before invoking pip.

Alon Barad
Alon Barad
6 views•5 min read