[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