[Git][java-team/netty][master] CVE-2026-33871
Bastien Roucariès (@rouca)
gitlab at salsa.debian.org
Mon Apr 6 14:57:30 BST 2026
Bastien Roucariès pushed to branch master at Debian Java Maintainers / netty
Commits:
1a58ead9 by Bastien Roucariès at 2026-04-06T15:56:24+02:00
CVE-2026-33871
- - - - -
4 changed files:
- debian/changelog
- + debian/patches/CVE-2025-58057_post1.patch
- + debian/patches/CVE-2026-33871.patch
- debian/patches/series
Changes:
=====================================
debian/changelog
=====================================
@@ -1,3 +1,24 @@
+netty (1:4.1.48-17) unstable; urgency=medium
+
+ * Team upload
+ * Fix a performance regression for CVE-2025-58057
+ A recent change changed JdkZlibDecoder to fire
+ ctx.fireChannelRead() on every inflate iteration (~8KB output) when
+ maxAllocation is 0. For a typical ~150KB HTTP response this produces
+ ~19 small buffer allocations and ~19 pipeline dispatches through the
+ internal EmbeddedChannel used by HttpContentDecoder, causing a 30-35%
+ throughput regression even in aggregated mode (where chunk count is
+ irrelevant downstream).
+ * Fix CVE-2026-33871 (Closes: #1132230):
+ a remote user can trigger a Denial of Service (DoS) against a Netty
+ HTTP/2 server by sending a flood of `CONTINUATION` frames. The
+ server's lack of a limit on the number of `CONTINUATION` frames,
+ combined with a bypass of existing size-based mitigations using
+ zero-byte frames, allows an user to cause excessive CPU consumption
+ with minimal bandwidth, rendering the server unresponsive
+
+ -- Bastien Roucariès <rouca at debian.org> Mon, 06 Apr 2026 15:55:51 +0200
+
netty (1:4.1.48-16) unstable; urgency=medium
* Team upload
=====================================
debian/patches/CVE-2025-58057_post1.patch
=====================================
@@ -0,0 +1,137 @@
+From: Netty Project Bot <78738768+netty-project-bot at users.noreply.github.com>
+Date: Mon, 6 Apr 2026 15:36:34 +0200
+Subject: [PATCH] Auto-port 4.1: JdkZlibDecoder: accumulate decompressed
+ output before firing channelRead (#16532)
+
+Auto-port of #16510 to 4.1
+Cherry-picked commit: a7fbb6f84625ef29733a1506ed3520e3c21d5247
+
+---
+Motivation:
+
+A recent change (9d804c54ce962408ae6418255a83a13924f7145d) changed
+JdkZlibDecoder to fire
+ctx.fireChannelRead() on every inflate iteration (~8KB output) when
+maxAllocation is 0. For a typical ~150KB HTTP response this produces
+~19 small buffer allocations and ~19 pipeline dispatches through the
+internal EmbeddedChannel used by HttpContentDecoder, causing a 30-35%
+throughput regression even in aggregated mode (where chunk count is
+irrelevant downstream).
+
+Modifications:
+
+Accumulate decompressed output up to 64KB (DEFAULT_MAX_FORWARD_BYTES)
+before firing ctx.fireChannelRead(). The buffer grows naturally via
+prepareDecompressBuffer() until the threshold, then fires and starts a
+new buffer. Any remaining data fires in the finally block as before.
+
+Memory per in-flight buffer is bounded to 64KB regardless of the
+compressed input size.
+
+Result:
+
+Throughput is restored to pre-regression levels. Chunks per response
+drop from ~163 to ~6 for a 150KB payload.
+
+Co-authored-by: Francesco Nigro <nigro.fra at gmail.com>
+
+origin: https://github.com/netty/netty/commit/10c1603cbab5e72a029521058eb35e15a8b7c7c5
+---
+ .../io/netty/handler/codec/compression/CompressionUtil.java | 4 ++++
+ .../java/io/netty/handler/codec/compression/JZlibDecoder.java | 6 +++++-
+ .../io/netty/handler/codec/compression/JdkZlibDecoder.java | 10 +++++++---
+ 3 files changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/codec/src/main/java/io/netty/handler/codec/compression/CompressionUtil.java b/codec/src/main/java/io/netty/handler/codec/compression/CompressionUtil.java
+index f25f1ee..b65723e 100644
+--- a/codec/src/main/java/io/netty/handler/codec/compression/CompressionUtil.java
++++ b/codec/src/main/java/io/netty/handler/codec/compression/CompressionUtil.java
+@@ -16,11 +16,15 @@
+ package io.netty.handler.codec.compression;
+
+ import io.netty.buffer.ByteBuf;
++import io.netty.util.internal.SystemPropertyUtil;
+
+ import java.nio.ByteBuffer;
+
+ final class CompressionUtil {
+
++ static final int DEFAULT_MAX_FORWARD_BYTES = SystemPropertyUtil.getInt(
++ "io.netty.compression.defaultMaxForwardBytes", 64 * 1024);
++
+ private CompressionUtil() { }
+
+ static void checkChecksum(ByteBufChecksum checksum, ByteBuf uncompressed, int currentChecksum) {
+diff --git a/codec/src/main/java/io/netty/handler/codec/compression/JZlibDecoder.java b/codec/src/main/java/io/netty/handler/codec/compression/JZlibDecoder.java
+index 9bc684e..7ef6f02 100644
+--- a/codec/src/main/java/io/netty/handler/codec/compression/JZlibDecoder.java
++++ b/codec/src/main/java/io/netty/handler/codec/compression/JZlibDecoder.java
+@@ -28,6 +28,8 @@ public class JZlibDecoder extends ZlibDecoder {
+
+ private final Inflater z = new Inflater();
+ private byte[] dictionary;
++ private static final int DEFAULT_MAX_FORWARD_BYTES = CompressionUtil.DEFAULT_MAX_FORWARD_BYTES;
++ private final int maxForwardBytes;
+ private boolean needsRead;
+ private volatile boolean finished;
+
+@@ -74,6 +76,7 @@ public class JZlibDecoder extends ZlibDecoder {
+ */
+ public JZlibDecoder(ZlibWrapper wrapper, int maxAllocation) {
+ super(maxAllocation);
++ this.maxForwardBytes = maxAllocation > 0 ? maxAllocation : DEFAULT_MAX_FORWARD_BYTES;
+
+ ObjectUtil.checkNotNull(wrapper, "wrapper");
+
+@@ -107,6 +110,7 @@ public class JZlibDecoder extends ZlibDecoder {
+ */
+ public JZlibDecoder(byte[] dictionary, int maxAllocation) {
+ super(maxAllocation);
++ this.maxForwardBytes = maxAllocation > 0 ? maxAllocation : DEFAULT_MAX_FORWARD_BYTES;
+ this.dictionary = ObjectUtil.checkNotNull(dictionary, "dictionary");
+ int resultCode;
+ resultCode = z.inflateInit(JZlib.W_ZLIB);
+@@ -168,7 +172,7 @@ public class JZlibDecoder extends ZlibDecoder {
+ int outputLength = z.next_out_index - oldNextOutIndex;
+ if (outputLength > 0) {
+ decompressed.writerIndex(decompressed.writerIndex() + outputLength);
+- if (maxAllocation == 0) {
++ if (maxAllocation == 0 && decompressed.readableBytes() >= maxForwardBytes) {
+ // If we don't limit the maximum allocations we should just
+ // forward the buffer directly.
+ ByteBuf buffer = decompressed;
+diff --git a/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibDecoder.java b/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibDecoder.java
+index 426b84e..657c3a3 100644
+--- a/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibDecoder.java
++++ b/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibDecoder.java
+@@ -59,6 +59,9 @@ public class JdkZlibDecoder extends ZlibDecoder {
+ private int xlen = -1;
+ private boolean needsRead;
+
++ private static final int DEFAULT_MAX_FORWARD_BYTES = CompressionUtil.DEFAULT_MAX_FORWARD_BYTES;
++ private final int maxForwardBytes;
++
+ private volatile boolean finished;
+
+ private boolean decideZlibOrNone;
+@@ -144,6 +147,7 @@ public class JdkZlibDecoder extends ZlibDecoder {
+
+ private JdkZlibDecoder(ZlibWrapper wrapper, byte[] dictionary, boolean decompressConcatenated, int maxAllocation) {
+ super(maxAllocation);
++ this.maxForwardBytes = maxAllocation > 0 ? maxAllocation : DEFAULT_MAX_FORWARD_BYTES;
+
+ ObjectUtil.checkNotNull(wrapper, "wrapper");
+
+@@ -241,9 +245,9 @@ public class JdkZlibDecoder extends ZlibDecoder {
+ if (crc != null) {
+ crc.update(outArray, outIndex, outputLength);
+ }
+- if (maxAllocation == 0) {
+- // If we don't limit the maximum allocations we should just
+- // forward the buffer directly.
++ if (maxAllocation == 0 && decompressed.readableBytes() >= maxForwardBytes) {
++ // Forward the buffer once it exceeds the threshold to bound memory
++ // while avoiding excessive fireChannelRead calls.
+ ByteBuf buffer = decompressed;
+ decompressed = null;
+ needsRead = false;
=====================================
debian/patches/CVE-2026-33871.patch
=====================================
@@ -0,0 +1,357 @@
+From: Norman Maurer <norman_maurer at apple.com>
+Date: Tue, 24 Mar 2026 13:39:52 +0100
+Subject: [PATCH] Limit the number of Continuation frames per HTTP2 Headers
+ (#13969)
+
+Motivation:
+
+We should limit the number of continuation frames that the remote peer
+is allowed to sent per headers.
+
+Modifications:
+
+- Limit the number of continuation frames by default to 16 and allow the
+user to change this.
+- Add unit test
+
+Result:
+
+Do some more validations to guard against resource usage
+
+origin: backport, https://github.com/netty/netty/commit/9f47a7b6846e6c7cb0481789be51788944042b85
+---
+ .../AbstractHttp2ConnectionHandlerBuilder.java | 28 +++++++++++-
+ .../codec/http2/DefaultHttp2FrameReader.java | 46 +++++++++++++++++--
+ .../netty/handler/codec/http2/Http2CodecUtil.java | 2 +-
+ .../codec/http2/Http2FrameCodecBuilder.java | 14 +++++-
+ .../codec/http2/Http2MultiplexCodecBuilder.java | 14 +++++-
+ .../codec/http2/DefaultHttp2FrameReaderTest.java | 53 ++++++++++++++++++++++
+ 6 files changed, 149 insertions(+), 8 deletions(-)
+
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/AbstractHttp2ConnectionHandlerBuilder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/AbstractHttp2ConnectionHandlerBuilder.java
+index 572da55..e463e34 100644
+--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/AbstractHttp2ConnectionHandlerBuilder.java
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/AbstractHttp2ConnectionHandlerBuilder.java
+@@ -13,7 +13,6 @@
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+-
+ package io.netty.handler.codec.http2;
+
+ import io.netty.channel.Channel;
+@@ -116,6 +115,7 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+ private int maxDecodedRstFramesSecondsPerWindow = 30;
+ private Integer maxEncodedRstFramesPerWindow;
+ private int maxEncodedRstFramesSecondsPerWindow = 30;
++ private int maxSmallContinuationFrames = Http2CodecUtil.DEFAULT_MAX_SMALL_CONTINUATION_FRAME;
+
+ /**
+ * Sets the {@link Http2Settings} to use for the initial connection settings exchange.
+@@ -470,6 +470,30 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+ return self();
+ }
+
++ /**
++ * Returns the maximum number of small CONTINUATION frames per HEADERS block that are allowed
++ * before the connection is closed. Small is defined as 8 KiB, half the minimum allowed HTTP2 frame size.
++ * This setting is to protect against the remote peer flooding us with such frames.
++ *
++ * {@code 0} means no protection is in place.
++ */
++ protected int decoderEnforceMaxSmallContinuationFrames() {
++ return maxSmallContinuationFrames;
++ }
++
++ /**
++ * Returns the maximum number of small CONTINUATION frames per HEADERS block that are allowed
++ * before the connection is closed. Small is defined as 8 KiB, half the minimum allowed HTTP2 frame size.
++ * This setting is to protect against the remote peer flooding us with such frames.
++ * {@code 0} means no protection should be applied.
++ */
++ protected B decoderEnforceMaxSmallContinuationFrames(int maxSmallContinuationFrames) {
++ enforceNonCodecConstraints("maxSmallContinuationFrames");
++ this.maxSmallContinuationFrames = checkPositiveOrZero(
++ maxSmallContinuationFrames, "maxSmallContinuationFrames");
++ return self();
++ }
++
+ /**
+ * Determine if settings frame should automatically be acknowledged and applied.
+ * @return this.
+@@ -545,7 +569,7 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+ Long maxHeaderListSize = initialSettings.maxHeaderListSize();
+ Http2FrameReader reader = new DefaultHttp2FrameReader(new DefaultHttp2HeadersDecoder(isValidateHeaders(),
+ maxHeaderListSize == null ? DEFAULT_HEADER_LIST_SIZE : maxHeaderListSize,
+- /* initialHuffmanDecodeCapacity= */ -1));
++ /* initialHuffmanDecodeCapacity= */ -1), maxSmallContinuationFrames);
+ Http2FrameWriter writer = encoderIgnoreMaxHeaderListSize == null ?
+ new DefaultHttp2FrameWriter(headerSensitivityDetector()) :
+ new DefaultHttp2FrameWriter(headerSensitivityDetector(), encoderIgnoreMaxHeaderListSize);
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameReader.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameReader.java
+index cc63b28..4dd5edf 100644
+--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameReader.java
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameReader.java
+@@ -18,12 +18,14 @@ import io.netty.buffer.ByteBuf;
+ import io.netty.buffer.ByteBufAllocator;
+ import io.netty.channel.ChannelHandlerContext;
+ import io.netty.handler.codec.http2.Http2FrameReader.Configuration;
++import io.netty.util.internal.ObjectUtil;
+ import io.netty.util.internal.PlatformDependent;
+ import io.netty.util.internal.UnstableApi;
+
+ import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_FRAME_SIZE;
+ import static io.netty.handler.codec.http2.Http2CodecUtil.FRAME_HEADER_LENGTH;
+ import static io.netty.handler.codec.http2.Http2CodecUtil.INT_FIELD_LENGTH;
++import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_FRAME_SIZE_LOWER_BOUND;
+ import static io.netty.handler.codec.http2.Http2CodecUtil.PING_FRAME_PAYLOAD_LENGTH;
+ import static io.netty.handler.codec.http2.Http2CodecUtil.PRIORITY_ENTRY_LENGTH;
+ import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_INITIAL_WINDOW_SIZE;
+@@ -32,6 +34,7 @@ import static io.netty.handler.codec.http2.Http2CodecUtil.SETTING_ENTRY_LENGTH;
+ import static io.netty.handler.codec.http2.Http2CodecUtil.headerListSizeExceeded;
+ import static io.netty.handler.codec.http2.Http2CodecUtil.isMaxFrameSizeValid;
+ import static io.netty.handler.codec.http2.Http2CodecUtil.readUnsignedInt;
++import static io.netty.handler.codec.http2.Http2Error.ENHANCE_YOUR_CALM;
+ import static io.netty.handler.codec.http2.Http2Error.FLOW_CONTROL_ERROR;
+ import static io.netty.handler.codec.http2.Http2Error.FRAME_SIZE_ERROR;
+ import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
+@@ -53,6 +56,7 @@ import static io.netty.handler.codec.http2.Http2FrameTypes.WINDOW_UPDATE;
+ */
+ @UnstableApi
+ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSizePolicy, Configuration {
++ private static final int FRAGMENT_THRESHOLD = MAX_FRAME_SIZE_LOWER_BOUND / 2;
+ private final Http2HeadersDecoder headersDecoder;
+
+ /**
+@@ -69,7 +73,8 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
+ private Http2Flags flags;
+ private int payloadLength;
+ private HeadersContinuation headersContinuation;
+- private int maxFrameSize;
++ private int maxFrameSize = DEFAULT_MAX_FRAME_SIZE;
++ private final int maxSmallContinuationFrames;
+
+ /**
+ * Create a new instance.
+@@ -90,8 +95,13 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
+ }
+
+ public DefaultHttp2FrameReader(Http2HeadersDecoder headersDecoder) {
+- this.headersDecoder = headersDecoder;
+- maxFrameSize = DEFAULT_MAX_FRAME_SIZE;
++ this(headersDecoder, Http2CodecUtil.DEFAULT_MAX_SMALL_CONTINUATION_FRAME);
++ }
++
++ public DefaultHttp2FrameReader(Http2HeadersDecoder headersDecoder, int maxSmallContinuationFrames) {
++ this.headersDecoder = ObjectUtil.checkNotNull(headersDecoder, "headersDecoder");
++ this.maxSmallContinuationFrames = ObjectUtil.checkPositiveOrZero(
++ maxSmallContinuationFrames, "maxSmallContinuationFrames");
+ }
+
+ @Override
+@@ -399,6 +409,12 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
+ + "Expected %d, but received %d.", headersContinuation.getStreamId(), streamId);
+ }
+
++ if (headersContinuation.numSmallFragments() >= maxSmallContinuationFrames) {
++ throw connectionError(ENHANCE_YOUR_CALM,
++ "Number of small consecutive continuations frames %d exceeds maximum: %d",
++ headersContinuation.numSmallFragments(), maxSmallContinuationFrames);
++ }
++
+ if (payloadLength < flags.getPaddingPresenceFieldLength()) {
+ throw streamError(streamId, FRAME_SIZE_ERROR,
+ "Frame length %d too small for padding.", payloadLength);
+@@ -656,6 +672,15 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
+ */
+ abstract int getStreamId();
+
++ /**
++ * Return the number of fragments that were used so far.
++ *
++ * @return the number of fragments
++ */
++ final int numSmallFragments() {
++ return builder.numSmallFragments();
++ }
++
+ /**
+ * Processes the next fragment for the current header block.
+ *
+@@ -684,6 +709,7 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
+ */
+ protected class HeadersBlockBuilder {
+ private ByteBuf headerBlock;
++ private int numSmallFragments;
+
+ /**
+ * The local header size maximum has been exceeded while accumulating bytes.
+@@ -694,6 +720,15 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
+ headerListSizeExceeded(headersDecoder.configuration().maxHeaderListSizeGoAway());
+ }
+
++ /**
++ * Return the number of fragments that was used so far.
++ *
++ * @return number of fragments.
++ */
++ int numSmallFragments() {
++ return numSmallFragments;
++ }
++
+ /**
+ * Adds a fragment to the block.
+ *
+@@ -705,6 +740,11 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
+ */
+ final void addFragment(ByteBuf fragment, int len, ByteBufAllocator alloc,
+ boolean endOfHeaders) throws Http2Exception {
++ if (maxSmallContinuationFrames > 0 && !endOfHeaders && len < FRAGMENT_THRESHOLD) {
++ // Only count of the fragment is not the end of header and if its < 8kb.
++ numSmallFragments++;
++ }
++
+ if (headerBlock == null) {
+ if (len > headersDecoder.configuration().maxHeaderListSizeGoAway()) {
+ headerSizeExceeded();
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2CodecUtil.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2CodecUtil.java
+index 303527c..4507fd7 100644
+--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2CodecUtil.java
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2CodecUtil.java
+@@ -117,7 +117,7 @@ public final class Http2CodecUtil {
+ public static final int SMALLEST_MAX_CONCURRENT_STREAMS = 100;
+ static final int DEFAULT_MAX_RESERVED_STREAMS = SMALLEST_MAX_CONCURRENT_STREAMS;
+ static final int DEFAULT_MIN_ALLOCATION_CHUNK = 1024;
+-
++ static final int DEFAULT_MAX_SMALL_CONTINUATION_FRAME = 16;
+ /**
+ * Calculate the threshold in bytes which should trigger a {@code GO_AWAY} if a set of headers exceeds this amount.
+ * @param maxHeaderListSize
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodecBuilder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodecBuilder.java
+index ef0cffe..937ec84 100644
+--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodecBuilder.java
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodecBuilder.java
+@@ -189,6 +189,17 @@ public class Http2FrameCodecBuilder extends
+ return super.encoderEnforceMaxRstFramesPerWindow(maxRstFramesPerWindow, secondsPerWindow);
+ }
+
++ @Override
++ public int decoderEnforceMaxSmallContinuationFrames() {
++ return super.decoderEnforceMaxSmallContinuationFrames();
++ }
++
++ @Override
++ public Http2FrameCodecBuilder decoderEnforceMaxSmallContinuationFrames(
++ int maxConsecutiveContinuationsFrames) {
++ return super.decoderEnforceMaxSmallContinuationFrames(maxConsecutiveContinuationsFrames);
++ }
++
+ /**
+ * Build a {@link Http2FrameCodec} object.
+ */
+@@ -202,7 +213,8 @@ public class Http2FrameCodecBuilder extends
+ Long maxHeaderListSize = initialSettings().maxHeaderListSize();
+ Http2FrameReader frameReader = new DefaultHttp2FrameReader(maxHeaderListSize == null ?
+ new DefaultHttp2HeadersDecoder(isValidateHeaders()) :
+- new DefaultHttp2HeadersDecoder(isValidateHeaders(), maxHeaderListSize));
++ new DefaultHttp2HeadersDecoder(isValidateHeaders(), maxHeaderListSize),
++ decoderEnforceMaxSmallContinuationFrames());
+
+ if (frameLogger() != null) {
+ frameWriter = new Http2OutboundFrameLogger(frameWriter, frameLogger());
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodecBuilder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodecBuilder.java
+index da097ec..46d7b76 100644
+--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodecBuilder.java
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodecBuilder.java
+@@ -218,6 +218,17 @@ public class Http2MultiplexCodecBuilder
+ return super.encoderEnforceMaxRstFramesPerWindow(maxRstFramesPerWindow, secondsPerWindow);
+ }
+
++ @Override
++ public int decoderEnforceMaxSmallContinuationFrames() {
++ return super.decoderEnforceMaxSmallContinuationFrames();
++ }
++
++ @Override
++ public Http2MultiplexCodecBuilder decoderEnforceMaxSmallContinuationFrames(
++ int maxConsecutiveContinuationsFrames) {
++ return super.decoderEnforceMaxSmallContinuationFrames(maxConsecutiveContinuationsFrames);
++ }
++
+ @Override
+ public Http2MultiplexCodec build() {
+ Http2FrameWriter frameWriter = this.frameWriter;
+@@ -228,7 +239,8 @@ public class Http2MultiplexCodecBuilder
+ Long maxHeaderListSize = initialSettings().maxHeaderListSize();
+ Http2FrameReader frameReader = new DefaultHttp2FrameReader(maxHeaderListSize == null ?
+ new DefaultHttp2HeadersDecoder(isValidateHeaders()) :
+- new DefaultHttp2HeadersDecoder(isValidateHeaders(), maxHeaderListSize));
++ new DefaultHttp2HeadersDecoder(isValidateHeaders(), maxHeaderListSize),
++ decoderEnforceMaxSmallContinuationFrames());
+
+ if (frameLogger() != null) {
+ frameWriter = new Http2OutboundFrameLogger(frameWriter, frameLogger());
+diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2FrameReaderTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2FrameReaderTest.java
+index 61c5a08..b4371d1 100644
+--- a/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2FrameReaderTest.java
++++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2FrameReaderTest.java
+@@ -104,6 +104,59 @@ public class DefaultHttp2FrameReaderTest {
+ }
+ }
+
++ @Test
++ public void readHeaderFrameAndContinuationFrameExceedMax() throws Http2Exception {
++ frameReader = new DefaultHttp2FrameReader(new DefaultHttp2HeadersDecoder(true), 2);
++ final int streamId = 1;
++
++ final ByteBuf input = Unpooled.buffer();
++ try {
++ Http2Headers headers = new DefaultHttp2Headers()
++ .authority("foo")
++ .method("get")
++ .path("/")
++ .scheme("https");
++ writeHeaderFrame(input, streamId, headers,
++ new Http2Flags().endOfHeaders(false).endOfStream(true));
++ writeContinuationFrame(input, streamId, new DefaultHttp2Headers().add("foo", "bar"),
++ new Http2Flags().endOfHeaders(false));
++ writeContinuationFrame(input, streamId, new DefaultHttp2Headers().add("foo2", "bar2"),
++ new Http2Flags().endOfHeaders(false));
++
++ Http2Exception ex = assertThrows(Http2Exception.class, new Executable() {
++ @Override
++ public void execute() throws Throwable {
++ frameReader.readFrame(ctx, input, listener);
++ }
++ });
++ assertEquals(Http2Error.ENHANCE_YOUR_CALM, ex.error());
++ } finally {
++ input.release();
++ }
++ }
++
++ @Test
++ public void readHeaderFrameAndContinuationFrameDontExceedMax() throws Http2Exception {
++ frameReader = new DefaultHttp2FrameReader(new DefaultHttp2HeadersDecoder(true), 2);
++ final int streamId = 1;
++
++ final ByteBuf input = Unpooled.buffer();
++ try {
++ Http2Headers headers = new DefaultHttp2Headers()
++ .authority("foo")
++ .method("get")
++ .path("/")
++ .scheme("https");
++ writeHeaderFrame(input, streamId, headers,
++ new Http2Flags().endOfHeaders(false).endOfStream(true));
++ writeContinuationFrame(input, streamId, new DefaultHttp2Headers().add("foo", "bar"),
++ new Http2Flags().endOfHeaders(false));
++ frameReader.readFrame(ctx, input, listener);
++ } finally {
++ input.release();
++ }
++ }
++
+ @Test
+ public void readUnknownFrame() throws Http2Exception {
+ ByteBuf input = Unpooled.buffer();
=====================================
debian/patches/series
=====================================
@@ -32,3 +32,5 @@ CVE-2025-55163_2.patch
CVE-2025-58057.patch
CVE-2025-58056.patch
CVE-2025-67735.patch
+CVE-2025-58057_post1.patch
+CVE-2026-33871.patch
View it on GitLab: https://salsa.debian.org/java-team/netty/-/commit/1a58ead93eabf86495195fca2eab568833093aa3
--
View it on GitLab: https://salsa.debian.org/java-team/netty/-/commit/1a58ead93eabf86495195fca2eab568833093aa3
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20260406/e04ddcdb/attachment.htm>
More information about the pkg-java-commits
mailing list