Mar 1, 2026·6 min read·110 visits
Multer < 2.1.0 fails to delete temporary files if a request errors out while an asynchronous file filter is running. Attackers can flood the server with requests that trigger this condition, filling the disk and crashing the application.
A critical resource exhaustion vulnerability exists in the Multer Node.js middleware versions prior to 2.1.0. The issue arises from a race condition between asynchronous file filtering and stream error handling. When a request triggers an error during the processing of a multipart stream, files that were pending validation in an asynchronous `fileFilter` are not properly cleaned up from the disk. This allows remote attackers to exhaust the server's storage capacity by repeatedly sending crafted requests, leading to a Denial of Service (DoS).
Multer is a popular middleware for handling multipart/form-data in Node.js applications, primarily used for file uploads. It processes incoming file streams, writes them to a destination (disk or memory), and provides hooks for validation via the fileFilter option. CVE-2026-3304 identifies a logic flaw in how Multer manages resource lifecycles when these validation hooks operate asynchronously.
The core of the vulnerability is a desynchronization between the global request state and individual file processing. When Multer receives a file, it may write it to a temporary location before deciding whether to keep it (based on fileFilter). If the fileFilter is asynchronous—common for lookups like malware scanning or quota checking—the underlying multipart parser (Busboy) continues processing the rest of the request stream.
If a fatal error occurs in the stream (e.g., a malformed subsequent part) while the fileFilter is still pending, the global error handler is triggered. However, in vulnerable versions, the callback for the pending fileFilter does not check this global error state upon completion. Consequently, the temporary file written to disk is effectively "orphaned." It is neither passed to the application nor deleted, remaining on the filesystem indefinitely. Repeated exploitation leads to complete disk exhaustion and service unavailability.
The vulnerability stems from the implementation of the make-middleware.js module in Multer. Specifically, it involves the interaction between the appender (responsible for writing data) and the fileFilter (responsible for validation).
When a file header is parsed, Multer invokes appender.insertPlaceholder. If the configured storage engine is DiskStorage, this creates a file on disk immediately. Multer then invokes the user-provided fileFilter. The logic flaw resides in the callback wrapper for this filter.
Prior to version 2.1.0, the callback only handled errors explicitly passed to it or the boolean decision to include the file. It failed to inspect the errorOccured flag, which tracks the health of the overall request stream. If the multipart parser encountered a protocol violation (such as a part missing the Content-Disposition name) after the file processing started but before the asynchronous filter completed, the errorOccured flag would be set to true.
However, when the asynchronous filter eventually resolved, the code proceeded as if the stream were healthy. Crucially, it bypassed the appender.removePlaceholder(placeholder) call that is necessary to clean up files when an operation is aborted. This specific execution path—async wait combined with stream failure—creates a zombie file on the filesystem.
The fix was applied in lib/make-middleware.js by introducing a check for the errorOccured state within the fileFilter callback. This ensures that if the request has already failed, the pending file is immediately cleaned up.
Vulnerable Code (Simplified):
// Inside make-middleware.js
fileFilter(req, file, function (err, includeFile) {
if (err) {
appender.removePlaceholder(placeholder)
return next(err)
}
if (!includeFile) {
appender.removePlaceholder(placeholder)
return fileStream.resume()
}
// ... proceed to save file ...
// CRITICAL MISSING CHECK: Does not verify if the request crashed elsewhere
})Patched Code:
The patch introduces a guard clause at the very beginning of the callback. This logic acknowledges that if the request stream has already error-ed out (due to malformed data later in the stream), the current file is irrelevant and must be removed.
// Inside make-middleware.js (Fixed)
fileFilter(req, file, function (err, includeFile) {
// NEW: Check global error state before proceeding
if (errorOccured) {
appender.removePlaceholder(placeholder)
return fileStream.resume()
}
if (err) {
appender.removePlaceholder(placeholder)
return next(err)
}
if (!includeFile) {
appender.removePlaceholder(placeholder)
return fileStream.resume()
}
// ... proceed to save file ...
})This simple addition ensures that the removePlaceholder method is called even when the error originated outside the scope of the current file's filter function.
To exploit CVE-2026-3304, an attacker does not need authentication or special privileges. They simply need to send a crafted multipart/form-data request to an endpoint utilizing Multer with an asynchronous fileFilter. The attack relies on timing and stream ordering.
Attack Steps:
file1.png).file1.png, writes it to the temporary directory, and calls the asynchronous fileFilter (e.g., checking if the file signature is allowed). This pauses processing for this specific file while the Node.js event loop continues.Content-Disposition header but lack the required name parameter.errorOccured flag is set to true.fileFilter for file1.png completes. Because the vulnerable code doesn't check errorOccured, it assumes success or simply ignores the cleanup path. The request terminates, but file1.png remains in the temporary folder.By scripting this process to occur in a loop, an attacker can rapidly fill the server's disk space with orphaned temporary files.
The primary impact of this vulnerability is Denial of Service (DoS) via disk resource exhaustion. In a cloud environment or containerized deployment with ephemeral storage, the impact may be temporary until the container restarts. However, in persistent hosting environments, this can lead to prolonged downtime.
Consequences:
dest directory is on the root partition, the entire operating system may become unstable, affecting other services running on the same host.CVSS 4.0 Assessment:
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:NCVSS: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.0 | 2.1.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-459 |
| Vulnerability Type | Resource Exhaustion (DoS) |
| CVSS 4.0 | 8.7 (High) |
| Attack Vector | Network |
| Affected Component | make-middleware.js |
| Prerequisites | Asynchronous fileFilter configuration |
A path traversal vulnerability (CWE-22) in the Microsoft TypeSpec compiler core and associated emitter packages permits unvalidated user input to escape the designated output directory, resulting in arbitrary JSON and YAML file creation or modification on the host system.
A critical parser differential vulnerability exists in Nodemailer prior to version 9.1.0. An attacker can bypass recipient-domain validation checks by utilizing RFC 5322 comments, leading to unauthorized email routing.
An algorithmic complexity vulnerability in Nodemailer before version 9.1.0 allows remote attackers to block the Node.js event loop. This denial of service is triggered by processing large or complex lists of email addresses, leading to quadratic resource consumption.
Nodemailer (prior to version 9.1.0) is vulnerable to an IDN/Punycode domain allow-list bypass due to an interpretation conflict between legacy RFC-3492 codecs and modern UTS-46 Unicode parsers.
A missing authorization vulnerability (CWE-862) exists in n8n where AI Agent workflows executing as tools bypass the Sub-Workflow Caller Policy settings, allowing authenticated users with agent creation privileges to invoke unauthorized sub-workflows across project boundaries.
A Denial of Service (DoS) vulnerability exists in the xmldom library when parsing HTML-mode documents with mixed-case closing tags for raw-text or escapable raw-text elements like script, style, textarea, or title. This leads to algorithmic complexity issues and quadratic output amplification during DOM serialization.