high · 7.5CVE-2026-55833Jul 22, 2026

CVE-2026-55833: netty-codec-http SPDY zlib Decompression Bomb (DoS)

Shubham Kandhare
Security Engagement Manager, SecureLayer7

Netty keeps inflating a zlib-compressed SPDY header block even after the header-size limit fires, so an attacker can send roughly 12 KB on the wire and force the server to decompress 12 MB of header…

Packageio.netty:netty-codec-http
Ecosystemmaven
Affected>= 4.2.0.Final, <= 4.2.15.Final
Fixed in4.2.16.Final

The problem

SpdyHeaderBlockZlibDecoder in netty-codec-http does not stop decompression once the inner raw-header parser has set truncated=true on the frame. The zlib inflate loop continues consuming and allocating memory for the remainder of the declared field length.

An unauthenticated remote peer that can reach a Netty pipeline containing SpdyFrameCodec can send a single crafted HEADERS frame. A 12,253-byte compressed payload can force roughly 12 MiB of decode and skip work, giving an amplification ratio of about 1000x per request.

Proof of concept

A working proof-of-concept for CVE-2026-55833 in io.netty:netty-codec-http, with the exact payload below.

bash
# Published PoC (poc.zip attached to the GitHub advisory)
# Run the official reproducer:
bash ./poc/run.sh

# Expected fingerprint confirming the bug:
# NETTY_SPDY_ZLIB_DECODED_AFTER_LIMIT_TRIGGERED \
#   compressed_bytes=12253 \
#   declared_name_length=12582912 \
#   max_header_size=16 \
#   truncated=true \
#   invalid=false

# Wire-level SPDY HEADERS frame structure (derived from advisory):
# - Frame type:    HEADERS (0x0008)
# - Stream-ID:     nonzero (e.g. 0x00000001)
# - Length:        >= 4 bytes
# - Payload:       zlib stream compressed with the SPDY dictionary
#                  Header block declares name_length = 0x00C00000 (12582912 / 12 MiB)
#                  followed by 12,253 bytes of compressed data
#                  Raw block ends with zero-length value to reach END_HEADER_BLOCK
#                  so truncated=true but invalid=false after decoding

The root cause (CWE-400) is a missing early-exit guard in SpdyHeaderBlockZlibDecoder. When the raw-header parser increments its running byte count past maxHeaderSize it sets the frame's truncated flag and stops storing headers, but returns normally. The zlib decoder receives that normal return and continues calling inflate() to consume the rest of the declared field length, which can be arbitrarily large.

The patch in commit bb2ff68a1fb71cb4b0eb9a9e17b66c52aff680c6 adds a check so that once truncated is true the zlib decoder immediately stops decompression and discards any remaining compressed input, rather than continuing to inflate and skip bytes. The specific state that proves exploitability is truncated=true AND invalid=false: the size guard fired but the codec did not treat truncation as a terminal condition for the inflate loop.

The fix

Upgrade to netty-codec-http 4.2.16.Final (4.x line) or 4.1.136.Final (4.1.x line). If an immediate upgrade is not possible, place a compressed-frame-size or connection-rate limit in front of any SpdyFrameCodec pipeline to bound per-connection inflate work. No workaround exists inside the codec itself prior to the patch.

Reporter not attributed.

References: [1][2][3][4][5][6]

Related research