Multer vulnerable to Denial of Service via resource exhaustion
Description
Multer is a node.js middleware for handling multipart/form-data. A vulnerability in Multer prior to version 2.1.0 allows an attacker to trigger a Denial of Service (DoS) by dropping connection during file upload, potentially causing resource exhaustion. Users should upgrade to version 2.1.0 to receive a patch. No known workarounds are available.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Multer before 2.1.0 is vulnerable to Denial of Service via resource exhaustion when an attacker drops connection during file upload.
Vulnerability
Description
Multer is a Node.js middleware for handling multipart/form-data file uploads [1]. In versions prior to 2.1.0, a vulnerability exists where an attacker can trigger a Denial of Service (DoS) by dropping the connection during a file upload. This causes the server to not properly release allocated resources, leading to resource exhaustion [3][4].
Exploitation
An attacker can exploit this vulnerability by initiating a file upload request and then abruptly closing the connection. The attack can be performed remotely without authentication if the upload endpoint is publicly accessible. No special privileges are required [3].
Impact
Successful exploitation can consume server memory or file handles, eventually causing the server to become unresponsive. Repeated attacks can lead to a full DoS condition, impacting the availability of the application. No known workarounds exist [3][4].
Mitigation
The vulnerability is fixed in Multer version 2.1.0. Users are advised to upgrade immediately. There are no known workarounds for affected versions [3].
AI Insight generated on May 18, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
multernpm | < 2.1.0 | 2.1.0 |
Affected products
2- expressjs/multerv5Range: 0.0.0
Patches
1cccf0fe0e641🔒️ improve disconnect handling
2 files changed · +89 −21
lib/make-middleware.js+39 −21 modified@@ -28,24 +28,8 @@ function makeMiddleware (setup) { req.body = Object.create(null) - req.on('error', function (err) { - abortWithError(err) - }) - var busboy - - try { - busboy = Busboy({ - headers: req.headers, - limits: limits, - preservePath: preservePath, - defParamCharset: defParamCharset - }) - } catch (err) { - return next(err) - } - - var appender = new FileAppender(fileStrategy, req) + var appender = null var isDone = false var readFinished = false var errorOccured = false @@ -55,12 +39,14 @@ function makeMiddleware (setup) { function done (err) { if (isDone) return isDone = true - req.unpipe(busboy) + if (busboy) { + req.unpipe(busboy) + setImmediate(() => { + busboy.removeAllListeners() + }) + } drainStream(req) req.resume() - setImmediate(() => { - busboy.removeAllListeners() - }) next(err) } @@ -90,6 +76,38 @@ function makeMiddleware (setup) { abortWithError(new MulterError(code, optionalField)) } + function handleRequestFailure (err) { + if (isDone) return + if (busboy) busboy.destroy(err) + abortWithError(err) + } + + req.on('error', function (err) { + handleRequestFailure(err || new Error('Request error')) + }) + + req.on('aborted', function () { + handleRequestFailure(new Error('Request aborted')) + }) + + req.on('close', function () { + if (req.readableEnded) return + handleRequestFailure(new Error('Request closed')) + }) + + try { + busboy = Busboy({ + headers: req.headers, + limits: limits, + preservePath: preservePath, + defParamCharset: defParamCharset + }) + } catch (err) { + return next(err) + } + + appender = new FileAppender(fileStrategy, req) + // handle text field data busboy.on('field', function (fieldname, value, { nameTruncated, valueTruncated }) { if (fieldname == null) return abortWithCode('MISSING_FIELD_NAME')
test/error-handling.js+50 −0 modified@@ -7,6 +7,8 @@ var util = require('./_util') var multer = require('../') var stream = require('stream') var FormData = require('form-data') +var http = require('http') +var net = require('net') function withLimits (limits, fields) { var storage = multer.memoryStorage() @@ -277,4 +279,52 @@ describe('Error Handling', function () { done() }) }) + + it('should not hang when client aborts multipart upload', function (done) { + this.timeout(5000) + + var upload = multer({ storage: multer.memoryStorage() }).any() + + var server = http.createServer(function (req, res) { + var hung = false + + var timer = setTimeout(function () { + hung = true + server.close() + done(new Error('Middleware hung when client aborted request')) + }, 1000) + + upload(req, res, function (/* err */) { + if (hung) return + clearTimeout(timer) + server.close() + done() + }) + }) + + server.listen(0, function () { + var port = server.address().port + var boundary = 'PoC' + Date.now() + var sock = new net.Socket() + + sock.connect(port, '127.0.0.1', function () { + sock.write( + 'POST / HTTP/1.1\r\n' + + 'Host: localhost\r\n' + + 'Content-Type: multipart/form-data; boundary=' + boundary + '\r\n' + + 'Content-Length: 999999\r\n\r\n' + + '--' + boundary + '\r\n' + + 'Content-Disposition: form-data; name="file"; filename="test.bin"\r\n' + + 'Content-Type: application/octet-stream\r\n\r\n' + + 'AAAAAAAAAAAAAAAA' + ) + + setTimeout(function () { + sock.destroy() + }, 50) + }) + + sock.on('error', function () {}) + }) + }) })
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-v52c-386h-88mcghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-2359ghsaADVISORY
- cna.openjsf.org/security-advisories.htmlghsaWEB
- github.com/expressjs/multer/commit/cccf0fe0e64150c4f42ccf6654165c0d66b9adabghsaWEB
- github.com/expressjs/multer/security/advisories/GHSA-v52c-386h-88mcghsaWEB
- www.cve.org/CVERecordghsaWEB
News mentions
0No linked articles in our index yet.