[Git][java-team/netty][bookworm] 3 commits: Add patches

Bastien Roucariès (@rouca) gitlab at salsa.debian.org
Sat Nov 15 09:20:24 GMT 2025



Bastien Roucariès pushed to branch bookworm at Debian Java Maintainers / netty


Commits:
c67982fa by Bastien Roucariès at 2025-11-15T10:17:27+01:00
Add patches

- - - - -
70a6c640 by Bastien Roucariès at 2025-11-15T10:19:04+01:00
Add debian/salsa-ci.yml

Signed-off-by: Julien Plissonneau Duquène <sre4ever at free.fr>

- - - - -
3571b5bd by Bastien Roucariès at 2025-11-15T10:19:57+01:00
FInalize changelog

- - - - -


8 changed files:

- debian/changelog
- + debian/patches/CVE-2025-55163_1.patch
- + debian/patches/CVE-2025-55163_2.patch
- + debian/patches/CVE-2025-55163_before-1.patch
- + debian/patches/CVE-2025-58056.patch
- + debian/patches/CVE-2025-59419
- debian/patches/series
- + debian/salsa-ci.yml


Changes:

=====================================
debian/changelog
=====================================
@@ -1,3 +1,32 @@
+netty (1:4.1.48-7+deb12u2) bookworm-security; urgency=medium
+
+  * Team upload
+  * Fix CVE-2025-55163 (Closes: #1111105)
+    Netty is vulnerable to MadeYouReset DDoS.
+    This is a logical vulnerability in the HTTP/2 protocol,
+    that uses malformed HTTP/2 control frames in order to break
+    the max concurrent streams limit, which results in resource
+    exhaustion and distributed denial of service.
+  * Fix CVE-2025-58056 (Closes: #1113994)
+    when supplied with specially crafted input, BrotliDecoder and
+    certain other decompression decoders will allocate a large
+    number of reachable byte buffers, which can lead to
+    denial of service. BrotliDecoder.decompress has
+    no limit in how often it calls pull, decompressing
+    data 64K bytes at a time. The buffers are saved in
+    the output list, and remain reachable until OOM is hit.
+  * Fix CVE-2025-59419 (Closes: #1118282)
+    SMTP Command Injection Vulnerability Allowing Email Forgery
+    An SMTP Command Injection (CRLF Injection) vulnerability
+    in Netty's SMTP codec allows a remote attacker who can control
+    SMTP command parameters (e.g., an email recipient)
+    to forge arbitrary emails from the trusted server.
+    This bypasses standard email authentication and can
+    be used to impersonate executives and forge high-stakes
+    corporate communications.
+
+ -- Bastien Roucariès <rouca at debian.org>  Sat, 15 Nov 2025 10:19:43 +0100
+
 netty (1:4.1.48-7+deb12u1) bookworm-security; urgency=high
 
   * Team upload.


=====================================
debian/patches/CVE-2025-55163_1.patch
=====================================
@@ -0,0 +1,149 @@
+From: Norman Maurer <norman_maurer at apple.com>
+Date: Mon, 28 Jul 2025 08:25:35 -1000
+Subject: =?utf-8?q?HTTP2=3A_Http2ConnectionHandler_should_always_use_Http2C?=
+ =?utf-8?q?onnectionEncode=E2=80=A6_=28=2315518=29?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+…r (#15516)
+
+Motivation:
+
+We sometimes directly used the Http2FrameWriter which is not correct as
+someone might have supplied a custom Http2ConnectionEncoder
+
+Modifications:
+
+Use Http2ConnectionEncoder when writing RST frames
+
+Result:
+
+Don't by-pass Http2ConnectionEncoder
+
+origin: backport, https://github.com/netty/netty/commit/be53dc3c9acd9af2e20d0c3c07cd77115a594cf1
+bug: https://github.com/netty/netty/security/advisories/GHSA-prj3-ccx8-p6x4
+bug-github-pull: https://github.com/netty/netty/pull/15516
+---
+ .../codec/http2/Http2ConnectionHandler.java        |  6 +++---
+ .../codec/http2/Http2ConnectionHandlerTest.java    | 22 +++++++++++-----------
+ 2 files changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java
+index 909ca74..0dd73cb 100644
+--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java
+@@ -706,7 +706,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
+                 try {
+                     stream = encoder.connection().remote().createStream(streamId, true);
+                 } catch (Http2Exception e) {
+-                    resetUnknownStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
++                    encoder().writeRstStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
+                     return;
+                 }
+             }
+@@ -723,10 +723,10 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
+ 
+         if (stream == null) {
+             if (!outbound || connection().local().mayHaveCreatedStream(streamId)) {
+-                resetUnknownStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
++                encoder().writeRstStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
+             }
+         } else {
+-            resetStream(ctx, stream, http2Ex.error().code(), ctx.newPromise());
++            encoder().writeRstStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
+         }
+     }
+ 
+diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionHandlerTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionHandlerTest.java
+index 0143edc..90b0ef6 100644
+--- a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionHandlerTest.java
++++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionHandlerTest.java
+@@ -403,7 +403,7 @@ public class Http2ConnectionHandlerTest {
+         when(connection.isServer()).thenReturn(true);
+         when(stream.isHeadersSent()).thenReturn(false);
+         when(remote.lastStreamCreated()).thenReturn(STREAM_ID);
+-        when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID),
++        when(encoder.writeRstStream(eq(ctx), eq(STREAM_ID),
+                 eq(PROTOCOL_ERROR.code()), eq(promise))).thenReturn(future);
+ 
+         handler.exceptionCaught(ctx, e);
+@@ -413,7 +413,7 @@ public class Http2ConnectionHandlerTest {
+                 captor.capture(), eq(padding), eq(true), eq(promise));
+         Http2Headers headers = captor.getValue();
+         assertEquals(HttpResponseStatus.REQUEST_HEADER_FIELDS_TOO_LARGE.codeAsText(), headers.status());
+-        verify(frameWriter).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
++        verify(encoder).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
+     }
+ 
+     @Test
+@@ -427,14 +427,14 @@ public class Http2ConnectionHandlerTest {
+         when(connection.isServer()).thenReturn(true);
+         when(stream.isHeadersSent()).thenReturn(false);
+         when(remote.lastStreamCreated()).thenReturn(STREAM_ID);
+-        when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID),
++        when(encoder.writeRstStream(eq(ctx), eq(STREAM_ID),
+             eq(PROTOCOL_ERROR.code()), eq(promise))).thenReturn(future);
+ 
+         handler.exceptionCaught(ctx, e);
+ 
+         verify(encoder, never()).writeHeaders(eq(ctx), eq(STREAM_ID),
+             any(Http2Headers.class), eq(padding), eq(true), eq(promise));
+-        verify(frameWriter).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
++        verify(encoder).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
+     }
+ 
+     @Test
+@@ -448,14 +448,14 @@ public class Http2ConnectionHandlerTest {
+         when(connection.isServer()).thenReturn(false);
+         when(stream.isHeadersSent()).thenReturn(false);
+         when(remote.lastStreamCreated()).thenReturn(STREAM_ID);
+-        when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID),
++        when(encoder.writeRstStream(eq(ctx), eq(STREAM_ID),
+                 eq(PROTOCOL_ERROR.code()), eq(promise))).thenReturn(future);
+ 
+         handler.exceptionCaught(ctx, e);
+ 
+         verify(encoder, never()).writeHeaders(eq(ctx), eq(STREAM_ID),
+                 any(Http2Headers.class), eq(padding), eq(true), eq(promise));
+-        verify(frameWriter).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
++        verify(encoder).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
+     }
+ 
+     @Test
+@@ -484,14 +484,14 @@ public class Http2ConnectionHandlerTest {
+         when(connection.isServer()).thenReturn(true);
+         when(stream.isHeadersSent()).thenReturn(true);
+         when(remote.lastStreamCreated()).thenReturn(STREAM_ID);
+-        when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID),
++        when(encoder.writeRstStream(eq(ctx), eq(STREAM_ID),
+             eq(PROTOCOL_ERROR.code()), eq(promise))).thenReturn(future);
+         handler.exceptionCaught(ctx, e);
+ 
+         verify(encoder, never()).writeHeaders(eq(ctx), eq(STREAM_ID),
+             any(Http2Headers.class), eq(padding), eq(true), eq(promise));
+ 
+-        verify(frameWriter).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
++        verify(encoder).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
+     }
+ 
+     @Test
+@@ -508,15 +508,15 @@ public class Http2ConnectionHandlerTest {
+         when(connection.isServer()).thenReturn(true);
+         when(stream.isHeadersSent()).thenReturn(false);
+         when(remote.lastStreamCreated()).thenReturn(STREAM_ID);
+-        when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID),
+-            eq(Http2Error.PROTOCOL_ERROR.code()), eq(promise))).thenReturn(future);
++        when(encoder.writeRstStream(eq(ctx), eq(STREAM_ID),
++            eq(PROTOCOL_ERROR.code()), eq(promise))).thenReturn(future);
+         handler.exceptionCaught(ctx, e);
+ 
+         verify(remote).createStream(STREAM_ID, true);
+         verify(encoder).writeHeaders(eq(ctx), eq(STREAM_ID),
+             any(Http2Headers.class), eq(padding), eq(true), eq(promise));
+ 
+-        verify(frameWriter).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
++        verify(encoder).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
+     }
+ 
+     @Test


=====================================
debian/patches/CVE-2025-55163_2.patch
=====================================
@@ -0,0 +1,492 @@
+From: Norman Maurer <norman_maurer at apple.com>
+Date: Wed, 13 Aug 2025 14:14:00 +0200
+Subject: [PATCH] Merge commit from fork
+
+* Enforce the maximum number of RST frames that can be sent in window of time
+
+Motivation:
+
+A remote peer might be able to trigger an instance to generate and send RST frames by sending invalid frames on an existing stream. This can cause high resource usage and so might be abused by a remote peer.
+
+Modifications:
+
+Limit the number of RSTs that we allow to be generated and so send in a specific time window. If this limit is reached a GO_AWAY frame is send and the connection be closed.
+
+Result:
+
+Fix high resource usage that can be caused by a remote peer by trigger RST frames
+
+* Adjust testing
+
+* Address comments
+
+origin: backport, https://github.com/netty/netty/commit/009bd17b38a39fb1eecf9d22ea8ae8108afaac59
+bug: https://github.com/netty/netty/security/advisories/GHSA-prj3-ccx8-p6x4
+---
+ .../AbstractHttp2ConnectionHandlerBuilder.java     |  54 +++++-
+ .../codec/http2/Http2ConnectionHandlerBuilder.java |   8 +
+ .../codec/http2/Http2FrameCodecBuilder.java        |   6 +
+ .../codec/http2/Http2MaxRstFrameLimitEncoder.java  |  85 ++++++++
+ .../codec/http2/Http2MultiplexCodecBuilder.java    |   6 +
+ .../http2/Http2MaxRstFrameLimitEncoderTest.java    | 213 +++++++++++++++++++++
+ 6 files changed, 367 insertions(+), 5 deletions(-)
+ create mode 100644 codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameLimitEncoder.java
+ create mode 100644 codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MaxRstFrameLimitEncoderTest.java
+
+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 fc70dfe..572da55 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
+@@ -112,7 +112,10 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+     private int maxQueuedControlFrames = Http2CodecUtil.DEFAULT_MAX_QUEUED_CONTROL_FRAMES;
+     private int maxConsecutiveEmptyFrames = 2;
+     private Integer maxRstFramesPerWindow;
+-    private int secondsPerWindow = 30;
++    private Integer maxDecodedRstFramesPerWindow;
++    private int maxDecodedRstFramesSecondsPerWindow = 30;
++    private Integer maxEncodedRstFramesPerWindow;
++    private int maxEncodedRstFramesSecondsPerWindow = 30;
+ 
+     /**
+      * Sets the {@link Http2Settings} to use for the initial connection settings exchange.
+@@ -446,9 +449,24 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+      */
+     protected B decoderEnforceMaxRstFramesPerWindow(int maxRstFramesPerWindow, int secondsPerWindow) {
+         enforceNonCodecConstraints("decoderEnforceMaxRstFramesPerWindow");
+-        this.maxRstFramesPerWindow = checkPositiveOrZero(
++        this.maxDecodedRstFramesPerWindow = checkPositiveOrZero(
+                 maxRstFramesPerWindow, "maxRstFramesPerWindow");
+-        this.secondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
++        this.maxDecodedRstFramesSecondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
++        return self();
++    }
++
++    /**
++     * Sets the maximum number RST frames that are allowed per window before
++     * the connection is closed. This allows to protect against the remote peer that will trigger us to generate a flood
++     * of RST frames and so use up a lot of CPU.
++     *
++     * {@code 0} for any of the parameters means no protection should be applied.
++     */
++    protected B encoderEnforceMaxRstFramesPerWindow(int maxRstFramesPerWindow, int secondsPerWindow) {
++        enforceNonCodecConstraints("decoderEnforceMaxRstFramesPerWindow");
++        this.maxEncodedRstFramesPerWindow = checkPositiveOrZero(
++                maxRstFramesPerWindow, "maxRstFramesPerWindow");
++        this.maxEncodedRstFramesSecondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
+         return self();
+     }
+ 
+@@ -543,6 +561,21 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+         if (maxQueuedControlFrames != 0) {
+             encoder = new Http2ControlFrameLimitEncoder(encoder, maxQueuedControlFrames);
+         }
++        final int maxEncodedRstFrames;
++        if (maxEncodedRstFramesPerWindow == null) {
++            // Only enable by default on the server.
++            if (isServer()) {
++                maxEncodedRstFrames = DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER;
++            } else {
++                maxEncodedRstFrames = 0;
++            }
++        } else {
++            maxEncodedRstFrames = maxEncodedRstFramesPerWindow;
++        }
++        if (maxEncodedRstFrames > 0 && maxEncodedRstFramesSecondsPerWindow > 0) {
++            encoder = new Http2MaxRstFrameLimitEncoder(
++                    encoder, maxEncodedRstFrames, maxEncodedRstFramesSecondsPerWindow);
++        }
+         if (encoderEnforceMaxConcurrentStreams) {
+             if (connection.isServer()) {
+                 encoder.close();
+@@ -575,8 +608,19 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+         } else {
+             maxRstFrames = maxRstFramesPerWindow;
+         }
+-        if (maxRstFrames > 0 && secondsPerWindow > 0) {
+-            decoder = new Http2MaxRstFrameDecoder(decoder, maxRstFrames, secondsPerWindow);
++        final int maxDecodedRstFrames;
++        if (maxDecodedRstFramesPerWindow == null) {
++            // Only enable by default on the server.
++            if (isServer()) {
++                maxDecodedRstFrames = DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER;
++            } else {
++                maxDecodedRstFrames = 0;
++            }
++        } else {
++            maxDecodedRstFrames = maxDecodedRstFramesPerWindow;
++        }
++        if (maxDecodedRstFrames > 0 && maxDecodedRstFramesSecondsPerWindow > 0) {
++            decoder = new Http2MaxRstFrameDecoder(decoder, maxDecodedRstFrames, maxDecodedRstFramesSecondsPerWindow);
+         }
+         final T handler;
+         try {
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandlerBuilder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandlerBuilder.java
+index c6d1ce7..1d2ac71 100644
+--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandlerBuilder.java
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandlerBuilder.java
+@@ -19,6 +19,8 @@ package io.netty.handler.codec.http2;
+ import io.netty.handler.codec.http2.Http2HeadersEncoder.SensitivityDetector;
+ import io.netty.util.internal.UnstableApi;
+ 
++import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
++
+ /**
+  * Builder which builds {@link Http2ConnectionHandler} objects.
+  */
+@@ -98,6 +100,12 @@ public final class Http2ConnectionHandlerBuilder
+         return super.decoupleCloseAndGoAway(decoupleCloseAndGoAway);
+     }
+ 
++    @Override
++    public Http2ConnectionHandlerBuilder encoderEnforceMaxRstFramesPerWindow(
++            int maxRstFramesPerWindow, int secondsPerWindow) {
++        return super.encoderEnforceMaxRstFramesPerWindow(maxRstFramesPerWindow, secondsPerWindow);
++    }
++
+     @Override
+     public Http2ConnectionHandler build() {
+         return super.build();
+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 ab183e5..ef0cffe 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
+@@ -183,6 +183,12 @@ public class Http2FrameCodecBuilder extends
+         return super.decoderEnforceMaxRstFramesPerWindow(maxRstFramesPerWindow, secondsPerWindow);
+     }
+ 
++    @Override
++    public Http2FrameCodecBuilder encoderEnforceMaxRstFramesPerWindow(
++            int maxRstFramesPerWindow, int secondsPerWindow) {
++        return super.encoderEnforceMaxRstFramesPerWindow(maxRstFramesPerWindow, secondsPerWindow);
++    }
++
+     /**
+      * Build a {@link Http2FrameCodec} object.
+      */
+diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameLimitEncoder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameLimitEncoder.java
+new file mode 100644
+index 0000000..a36b3d7
+--- /dev/null
++++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameLimitEncoder.java
+@@ -0,0 +1,85 @@
++/*
++ * Copyright 2025 The Netty Project
++ *
++ * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
++ * "License"); you may not use this file except in compliance with the License. You may obtain a
++ * copy of the License at:
++ *
++ * https://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software distributed under the License
++ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
++ * or implied. See the License for the specific language governing permissions and limitations under
++ * the License.
++ */
++package io.netty.handler.codec.http2;
++
++import io.netty.channel.ChannelFuture;
++import io.netty.channel.ChannelHandlerContext;
++import io.netty.channel.ChannelPromise;
++import io.netty.util.internal.logging.InternalLogger;
++import io.netty.util.internal.logging.InternalLoggerFactory;
++
++import java.util.concurrent.TimeUnit;
++
++/**
++ * {@link DecoratingHttp2ConnectionEncoder} which guards against a remote peer that will trigger a massive amount
++ * of RST frames on an existing connection.
++ * This encoder will tear-down the connection once we reached the configured limit to reduce the risk of DDOS.
++ */
++final class Http2MaxRstFrameLimitEncoder extends DecoratingHttp2ConnectionEncoder {
++    private static final InternalLogger logger = InternalLoggerFactory.getInstance(Http2MaxRstFrameLimitEncoder.class);
++
++    private final long nanosPerWindow;
++    private final int maxRstFramesPerWindow;
++    private long lastRstFrameNano = System.nanoTime();
++    private int sendRstInWindow;
++    private Http2LifecycleManager lifecycleManager;
++
++    Http2MaxRstFrameLimitEncoder(Http2ConnectionEncoder delegate, int maxRstFramesPerWindow, int secondsPerWindow) {
++        super(delegate);
++        this.maxRstFramesPerWindow = maxRstFramesPerWindow;
++        this.nanosPerWindow = TimeUnit.SECONDS.toNanos(secondsPerWindow);
++    }
++
++    @Override
++    public void lifecycleManager(Http2LifecycleManager lifecycleManager) {
++        this.lifecycleManager = lifecycleManager;
++        super.lifecycleManager(lifecycleManager);
++    }
++
++    @Override
++    public ChannelFuture writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
++                                        ChannelPromise promise) {
++        ChannelFuture future = super.writeRstStream(ctx, streamId, errorCode, promise);
++        if (countRstFrameErrorCode(errorCode)) {
++            long currentNano = System.nanoTime();
++            if (currentNano - lastRstFrameNano >= nanosPerWindow) {
++                lastRstFrameNano = currentNano;
++                sendRstInWindow = 1;
++            } else {
++                sendRstInWindow++;
++                if (sendRstInWindow > maxRstFramesPerWindow) {
++                    Http2Exception exception = Http2Exception.connectionError(Http2Error.ENHANCE_YOUR_CALM,
++                            "Maximum number %d of RST frames frames reached within %d seconds", maxRstFramesPerWindow,
++                            TimeUnit.NANOSECONDS.toSeconds(nanosPerWindow));
++
++                    logger.debug("{} Maximum number {} of RST frames reached within {} seconds, " +
++                                    "closing connection with {} error", ctx.channel(), maxRstFramesPerWindow,
++                            TimeUnit.NANOSECONDS.toSeconds(nanosPerWindow), exception.error(),
++                            exception);
++                    // First notify the Http2LifecycleManager and then close the connection.
++                    lifecycleManager.onError(ctx, true, exception);
++                    ctx.close();
++                }
++            }
++        }
++
++        return future;
++    }
++
++    private boolean countRstFrameErrorCode(long errorCode) {
++        // Don't count CANCEL and NO_ERROR as these might be ok.
++        return errorCode != Http2Error.CANCEL.code() && errorCode != Http2Error.NO_ERROR.code();
++    }
++}
+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 0a38d4e..da097ec 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
+@@ -212,6 +212,12 @@ public class Http2MultiplexCodecBuilder
+         return super.decoderEnforceMaxRstFramesPerWindow(maxRstFramesPerWindow, secondsPerWindow);
+     }
+ 
++    @Override
++    public Http2MultiplexCodecBuilder encoderEnforceMaxRstFramesPerWindow(
++            int maxRstFramesPerWindow, int secondsPerWindow) {
++        return super.encoderEnforceMaxRstFramesPerWindow(maxRstFramesPerWindow, secondsPerWindow);
++    }
++
+     @Override
+     public Http2MultiplexCodec build() {
+         Http2FrameWriter frameWriter = this.frameWriter;
+diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MaxRstFrameLimitEncoderTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MaxRstFrameLimitEncoderTest.java
+new file mode 100644
+index 0000000..24c40fe
+--- /dev/null
++++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MaxRstFrameLimitEncoderTest.java
+@@ -0,0 +1,213 @@
++/*
++ * Copyright 2019 The Netty Project
++ *
++ * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
++ * "License"); you may not use this file except in compliance with the License. You may obtain a
++ * copy of the License at:
++ *
++ * https://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software distributed under the License
++ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
++ * or implied. See the License for the specific language governing permissions and limitations under
++ * the License.
++ */
++
++package io.netty.handler.codec.http2;
++
++import io.netty.buffer.ByteBuf;
++import io.netty.buffer.UnpooledByteBufAllocator;
++import io.netty.channel.Channel;
++import io.netty.channel.ChannelConfig;
++import io.netty.channel.ChannelFuture;
++import io.netty.channel.ChannelHandlerContext;
++import io.netty.channel.ChannelMetadata;
++import io.netty.channel.ChannelPromise;
++import io.netty.channel.DefaultChannelPromise;
++import io.netty.channel.DefaultMessageSizeEstimator;
++import io.netty.util.ReferenceCountUtil;
++import io.netty.util.concurrent.EventExecutor;
++import io.netty.util.concurrent.ImmediateEventExecutor;
++import org.junit.jupiter.api.AfterEach;
++import org.junit.jupiter.api.BeforeEach;
++import org.junit.jupiter.api.Test;
++import org.junit.jupiter.params.ParameterizedTest;
++import org.junit.jupiter.params.provider.EnumSource;
++import org.junit.jupiter.params.provider.ValueSource;
++import org.mockito.Mock;
++import org.mockito.MockitoAnnotations;
++import org.mockito.invocation.InvocationOnMock;
++import org.mockito.stubbing.Answer;
++
++import java.util.ArrayDeque;
++import java.util.Queue;
++
++import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_FRAME_SIZE;
++import static io.netty.handler.codec.http2.Http2Error.CANCEL;
++import static io.netty.handler.codec.http2.Http2Error.ENHANCE_YOUR_CALM;
++import static io.netty.handler.codec.http2.Http2Error.NO_ERROR;
++import static org.junit.jupiter.api.Assertions.assertTrue;
++import static org.mockito.Mockito.any;
++import static org.mockito.Mockito.anyInt;
++import static org.mockito.Mockito.anyLong;
++import static org.mockito.Mockito.atLeast;
++import static org.mockito.Mockito.doAnswer;
++import static org.mockito.Mockito.eq;
++import static org.mockito.Mockito.mock;
++import static org.mockito.Mockito.times;
++import static org.mockito.Mockito.verify;
++import static org.mockito.Mockito.when;
++
++/**
++ * Tests for {@link Http2MaxRstFrameLimitEncoder}.
++ */
++public class Http2MaxRstFrameLimitEncoderTest {
++
++    private Http2MaxRstFrameLimitEncoder encoder;
++
++    @Mock
++    private Http2FrameWriter writer;
++
++    @Mock
++    private ChannelHandlerContext ctx;
++
++    @Mock
++    private Channel channel;
++
++    @Mock
++    private Channel.Unsafe unsafe;
++
++    @Mock
++    private ChannelConfig config;
++
++    @Mock
++    private EventExecutor executor;
++
++    private final Queue<ChannelPromise> goAwayPromises = new ArrayDeque<ChannelPromise>();
++
++    /**
++     * Init fields and do mocking.
++     */
++    @BeforeEach
++    public void setup() throws Exception {
++        MockitoAnnotations.initMocks(this);
++        Http2FrameWriter.Configuration configuration = mock(Http2FrameWriter.Configuration.class);
++        Http2FrameSizePolicy frameSizePolicy = mock(Http2FrameSizePolicy.class);
++        when(writer.configuration()).thenReturn(configuration);
++        when(configuration.frameSizePolicy()).thenReturn(frameSizePolicy);
++        when(frameSizePolicy.maxFrameSize()).thenReturn(DEFAULT_MAX_FRAME_SIZE);
++
++        when(writer.writeRstStream(eq(ctx), anyInt(), anyLong(), any(ChannelPromise.class)))
++                .thenAnswer(new Answer<ChannelFuture>() {
++                    @Override
++                    public ChannelFuture answer(InvocationOnMock invocationOnMock) {
++                        return handlePromise(invocationOnMock, 3);
++                    }
++                });
++        when(writer.writeGoAway(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class),
++                any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
++            @Override
++            public ChannelFuture answer(InvocationOnMock invocationOnMock) {
++                ReferenceCountUtil.release(invocationOnMock.getArgument(3));
++                ChannelPromise promise = invocationOnMock.getArgument(4);
++                goAwayPromises.offer(promise);
++                return promise;
++            }
++        });
++        Http2Connection connection = new DefaultHttp2Connection(false);
++        connection.remote().flowController(new DefaultHttp2RemoteFlowController(connection));
++        connection.local().flowController(new DefaultHttp2LocalFlowController(connection).frameWriter(writer));
++
++        DefaultHttp2ConnectionEncoder defaultEncoder =
++                new DefaultHttp2ConnectionEncoder(connection, writer);
++        encoder = new Http2MaxRstFrameLimitEncoder(defaultEncoder, 2, 1);
++        DefaultHttp2ConnectionDecoder decoder =
++                new DefaultHttp2ConnectionDecoder(connection, encoder, mock(Http2FrameReader.class));
++        Http2ConnectionHandler handler = new Http2ConnectionHandlerBuilder()
++                .frameListener(mock(Http2FrameListener.class))
++                .codec(decoder, encoder).build();
++
++        // Set LifeCycleManager on encoder and decoder
++        when(ctx.channel()).thenReturn(channel);
++        when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
++        when(channel.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
++        when(executor.inEventLoop()).thenReturn(true);
++        doAnswer(new Answer<ChannelPromise>() {
++            @Override
++            public ChannelPromise answer(InvocationOnMock invocation) throws Throwable {
++                return newPromise();
++            }
++        }).when(ctx).newPromise();
++        when(ctx.executor()).thenReturn(executor);
++        when(channel.isActive()).thenReturn(false);
++        when(channel.config()).thenReturn(config);
++        when(channel.isWritable()).thenReturn(true);
++        when(channel.bytesBeforeUnwritable()).thenReturn(Long.MAX_VALUE);
++        when(config.getWriteBufferHighWaterMark()).thenReturn(Integer.MAX_VALUE);
++        when(config.getMessageSizeEstimator()).thenReturn(DefaultMessageSizeEstimator.DEFAULT);
++        ChannelMetadata metadata = new ChannelMetadata(false, 16);
++        when(channel.metadata()).thenReturn(metadata);
++        when(channel.unsafe()).thenReturn(unsafe);
++        handler.handlerAdded(ctx);
++    }
++
++    private ChannelPromise handlePromise(InvocationOnMock invocationOnMock, int promiseIdx) {
++        ChannelPromise promise = invocationOnMock.getArgument(promiseIdx);
++        return promise.setSuccess();
++    }
++
++    @AfterEach
++    public void teardown() {
++        // Close and release any buffered frames.
++        encoder.close();
++
++        // Notify all goAway ChannelPromise instances now as these will also release the retained ByteBuf for the
++        // debugData.
++        for (;;) {
++            ChannelPromise promise = goAwayPromises.poll();
++            if (promise == null) {
++                break;
++            }
++            promise.setSuccess();
++        }
++    }
++
++    @ParameterizedTest
++    @EnumSource(Http2Error.class)
++    public void testLimitRst(Http2Error error) {
++        assertTrue(encoder.writeRstStream(ctx, 1, error.code(), newPromise()).isSuccess());
++        assertTrue(encoder.writeRstStream(ctx, 1, error.code(), newPromise()).isSuccess());
++        verifyFlushAndClose(0, false);
++        assertTrue(encoder.writeRstStream(ctx, 1, error.code(), newPromise()).isSuccess());
++        if (error == CANCEL || error == NO_ERROR) {
++            // CANCEL and NO_ERROR are ignored as these will not be caused by a stream error.
++            verifyFlushAndClose(0, false);
++        } else {
++            verifyFlushAndClose(1, true);
++        }
++    }
++
++    @ParameterizedTest
++    @EnumSource(Http2Error.class)
++    public void testLimitRstReset(Http2Error error) throws Exception {
++        assertTrue(encoder.writeRstStream(ctx, 1, error.code(), newPromise()).isSuccess());
++        assertTrue(encoder.writeRstStream(ctx, 1, error.code(), newPromise()).isSuccess());
++        verifyFlushAndClose(0, false);
++        Thread.sleep(1000);
++        assertTrue(encoder.writeRstStream(ctx, 1, error.code(), newPromise()).isSuccess());
++        verifyFlushAndClose(0, false);
++    }
++
++    private void verifyFlushAndClose(int invocations, boolean failed) {
++        verify(ctx, atLeast(invocations)).flush();
++        verify(ctx, times(invocations)).close();
++        if (failed) {
++            verify(writer, times(1)).writeGoAway(eq(ctx), eq(Integer.MAX_VALUE), eq(ENHANCE_YOUR_CALM.code()),
++                    any(ByteBuf.class), any(ChannelPromise.class));
++        }
++    }
++
++    private ChannelPromise newPromise() {
++        return new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
++    }
++}


=====================================
debian/patches/CVE-2025-55163_before-1.patch
=====================================
@@ -0,0 +1,106 @@
+From: Debian Java Maintainers <pkg-java-maintainers at lists.alioth.debian.org>
+Date: Sat, 15 Nov 2025 10:14:12 +0100
+Subject: CVE-2025-55163_before-1
+
+commit 9b80d081ff3478c46152b012ae0e21f939467ac3
+Author: Norman Maurer <norman_maurer at apple.com>
+Date:   Sat Oct 28 20:49:44 2023 +0200
+
+Only enable the RST limit for servers by default (#13671)
+
+Motivation:
+
+We dont need to limit the number of RST frames per connection when we
+are bulding a codec for the client side.
+
+Modifications:
+
+Dont limit the numbers of RST frames per connection when building a
+codec for the client side.
+
+Result:
+
+Only add limit where needed
+
+origin: backport, https://github.com/netty/netty/commit/9b80d081ff3478c46152b012ae0e21f939467ac3
+bug-github-pull: https://github.com/netty/netty/pull/13671
+---
+ .../http2/AbstractHttp2ConnectionHandlerBuilder.java  | 19 ++++++++++++++++---
+ .../handler/codec/http2/Http2FrameCodecBuilder.java   |  4 ++--
+ .../codec/http2/Http2MultiplexCodecBuilder.java       |  4 ++--
+ 3 files changed, 20 insertions(+), 7 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 a904310..fc70dfe 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
+@@ -78,6 +78,8 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+ 
+     private static final SensitivityDetector DEFAULT_HEADER_SENSITIVITY_DETECTOR = Http2HeadersEncoder.NEVER_SENSITIVE;
+ 
++    private static final int DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER = 200;
++
+     // The properties that can always be set.
+     private Http2Settings initialSettings = Http2Settings.defaultSettings();
+     private Http2FrameListener frameListener;
+@@ -109,7 +111,7 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+     private boolean autoAckPingFrame = true;
+     private int maxQueuedControlFrames = Http2CodecUtil.DEFAULT_MAX_QUEUED_CONTROL_FRAMES;
+     private int maxConsecutiveEmptyFrames = 2;
+-    private int maxRstFramesPerWindow = 200;
++    private Integer maxRstFramesPerWindow;
+     private int secondsPerWindow = 30;
+ 
+     /**
+@@ -562,8 +564,19 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
+         if (maxConsecutiveEmptyDataFrames > 0) {
+             decoder = new Http2EmptyDataFrameConnectionDecoder(decoder, maxConsecutiveEmptyDataFrames);
+         }
+-        if (maxRstFramesPerWindow > 0 && secondsPerWindow > 0) {
+-            decoder = new Http2MaxRstFrameDecoder(decoder, maxRstFramesPerWindow, secondsPerWindow);
++        final int maxRstFrames;
++        if (maxRstFramesPerWindow == null) {
++            // Only enable by default on the server.
++            if (isServer()) {
++                maxRstFrames = DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER;
++            } else {
++                maxRstFrames = 0;
++            }
++        } else {
++            maxRstFrames = maxRstFramesPerWindow;
++        }
++        if (maxRstFrames > 0 && secondsPerWindow > 0) {
++            decoder = new Http2MaxRstFrameDecoder(decoder, maxRstFrames, secondsPerWindow);
+         }
+         final T handler;
+         try {
+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 241c9c5..ab183e5 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
+@@ -179,8 +179,8 @@ public class Http2FrameCodecBuilder extends
+ 
+     @Override
+     public Http2FrameCodecBuilder decoderEnforceMaxRstFramesPerWindow(
+-            int maxConsecutiveEmptyFrames, int secondsPerWindow) {
+-        return super.decoderEnforceMaxRstFramesPerWindow(maxConsecutiveEmptyFrames, secondsPerWindow);
++            int maxRstFramesPerWindow, int secondsPerWindow) {
++        return super.decoderEnforceMaxRstFramesPerWindow(maxRstFramesPerWindow, secondsPerWindow);
+     }
+ 
+     /**
+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 a3c0bed..0a38d4e 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
+@@ -208,8 +208,8 @@ public class Http2MultiplexCodecBuilder
+ 
+     @Override
+     public Http2MultiplexCodecBuilder decoderEnforceMaxRstFramesPerWindow(
+-            int maxConsecutiveEmptyFrames, int secondsPerWindow) {
+-        return super.decoderEnforceMaxRstFramesPerWindow(maxConsecutiveEmptyFrames, secondsPerWindow);
++            int maxRstFramesPerWindow, int secondsPerWindow) {
++        return super.decoderEnforceMaxRstFramesPerWindow(maxRstFramesPerWindow, secondsPerWindow);
+     }
+ 
+     @Override


=====================================
debian/patches/CVE-2025-58056.patch
=====================================
@@ -0,0 +1,111 @@
+From: Norman Maurer <norman_maurer at apple.com>
+Date: Wed, 3 Sep 2025 10:35:05 +0200
+Subject: Merge commit from fork (#15612)
+
+Motivation:
+
+We should ensure our decompressing decoders will fire their buffers
+through the pipeliner as fast as possible and so allow the user to take
+ownership of these as fast as possible. This is needed to reduce the
+risk of OOME as otherwise a small input might produce a large amount of
+data that can't be processed until all the data was decompressed in a
+loop. Beside this we also should ensure that other handlers that uses
+these decompressors will not buffer all of the produced data before
+processing it, which was true for HTTP and HTTP2.
+
+Modifications:
+
+- Adjust affected decoders (Brotli, Zstd and ZLib) to fire buffers
+  through the pipeline as soon as possible
+- Adjust HTTP / HTTP2 decompressors to do the same
+- Add testcase.
+
+Result:
+
+Less risk of OOME when doing decompressing
+
+Co-authored-by: yawkat <jonas.konrad at oracle.com>
+origin: backport, https://github.com/netty/netty/commit/39d3ecf8f0c57a7469ba927b2163d4cb4314b138
+bug: https://github.com/netty/netty/security/advisories/GHSA-3p8m-j85q-pgmj
+bug-debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1113994
+---
+ .../codec/compression/JZlibIntegrationTest.java    | 31 ++++++++++++++++++++++
+ .../codec/compression/JdkZlibIntegrationTest.java  | 31 ++++++++++++++++++++++
+ 2 files changed, 62 insertions(+)
+ create mode 100644 codec/src/test/java/io/netty/handler/codec/compression/JZlibIntegrationTest.java
+ create mode 100644 codec/src/test/java/io/netty/handler/codec/compression/JdkZlibIntegrationTest.java
+
+diff --git a/codec/src/test/java/io/netty/handler/codec/compression/JZlibIntegrationTest.java b/codec/src/test/java/io/netty/handler/codec/compression/JZlibIntegrationTest.java
+new file mode 100644
+index 0000000..252f134
+--- /dev/null
++++ b/codec/src/test/java/io/netty/handler/codec/compression/JZlibIntegrationTest.java
+@@ -0,0 +1,31 @@
++/*
++ * Copyright 2014 The Netty Project
++ *
++ * The Netty Project licenses this file to you under the Apache License,
++ * version 2.0 (the "License"); you may not use this file except in compliance
++ * with the License. You may obtain a copy of the License at:
++ *
++ *   https://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++ * License for the specific language governing permissions and limitations
++ * under the License.
++ */
++package io.netty.handler.codec.compression;
++
++import io.netty.channel.embedded.EmbeddedChannel;
++
++public class JZlibIntegrationTest extends AbstractIntegrationTest {
++
++    @Override
++    protected EmbeddedChannel createEncoder() {
++        return new EmbeddedChannel(new JZlibEncoder());
++    }
++
++    @Override
++    protected EmbeddedChannel createDecoder() {
++        return new EmbeddedChannel(new JZlibDecoder(0));
++    }
++}
+diff --git a/codec/src/test/java/io/netty/handler/codec/compression/JdkZlibIntegrationTest.java b/codec/src/test/java/io/netty/handler/codec/compression/JdkZlibIntegrationTest.java
+new file mode 100644
+index 0000000..6dca41d
+--- /dev/null
++++ b/codec/src/test/java/io/netty/handler/codec/compression/JdkZlibIntegrationTest.java
+@@ -0,0 +1,31 @@
++/*
++ * Copyright 2014 The Netty Project
++ *
++ * The Netty Project licenses this file to you under the Apache License,
++ * version 2.0 (the "License"); you may not use this file except in compliance
++ * with the License. You may obtain a copy of the License at:
++ *
++ *   https://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++ * License for the specific language governing permissions and limitations
++ * under the License.
++ */
++package io.netty.handler.codec.compression;
++
++import io.netty.channel.embedded.EmbeddedChannel;
++
++public class JdkZlibIntegrationTest extends AbstractIntegrationTest {
++
++    @Override
++    protected EmbeddedChannel createEncoder() {
++        return new EmbeddedChannel(new JdkZlibEncoder());
++    }
++
++    @Override
++    protected EmbeddedChannel createDecoder() {
++        return new EmbeddedChannel(new JdkZlibDecoder(0));
++    }
++}


=====================================
debian/patches/CVE-2025-59419
=====================================
@@ -0,0 +1,187 @@
+From: DepthFirst Disclosures <disclosures at depthfirst.com>
+Date: Tue, 14 Oct 2025 01:41:47 -0700
+Subject: CVE-2025-59419: Merge commit from fork
+
+* Patch 1 of 3
+
+* Patch 2 of 3
+
+* Patch 3 of 3
+
+* Fix indentation style
+
+* Update 2025
+
+* Optimize allocations
+
+* Update codec-smtp/src/main/java/io/netty/handler/codec/smtp/SmtpUtils.java
+
+Co-authored-by: Chris Vest <christianvest_hansen at apple.com>
+
+---------
+
+Co-authored-by: Norman Maurer <norman_maurer at apple.com>
+Co-authored-by: Chris Vest <christianvest_hansen at apple.com>
+origin: https://github.com/netty/netty/commit/2b3fddd3339cde1601f622b9ce5e54c39f24c3f9
+bug: https://github.com/netty/netty/security/advisories/GHSA-jq43-27x9-3v86
+bug-debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1118282
+---
+ .../handler/codec/smtp/DefaultSmtpRequest.java     |  2 +
+ .../io/netty/handler/codec/smtp/SmtpUtils.java     | 44 +++++++++++++
+ .../netty/handler/codec/smtp/SmtpRequestsTest.java | 73 ++++++++++++++++++++++
+ 3 files changed, 119 insertions(+)
+ create mode 100644 codec-smtp/src/test/java/io/netty/handler/codec/smtp/SmtpRequestsTest.java
+
+diff --git a/codec-smtp/src/main/java/io/netty/handler/codec/smtp/DefaultSmtpRequest.java b/codec-smtp/src/main/java/io/netty/handler/codec/smtp/DefaultSmtpRequest.java
+index 8f4d697..ae6acb4 100644
+--- a/codec-smtp/src/main/java/io/netty/handler/codec/smtp/DefaultSmtpRequest.java
++++ b/codec-smtp/src/main/java/io/netty/handler/codec/smtp/DefaultSmtpRequest.java
+@@ -43,6 +43,7 @@ public final class DefaultSmtpRequest implements SmtpRequest {
+      */
+     public DefaultSmtpRequest(SmtpCommand command, CharSequence... parameters) {
+         this.command = ObjectUtil.checkNotNull(command, "command");
++        SmtpUtils.validateSMTPParameters(parameters);
+         this.parameters = SmtpUtils.toUnmodifiableList(parameters);
+     }
+ 
+@@ -55,6 +56,7 @@ public final class DefaultSmtpRequest implements SmtpRequest {
+ 
+     DefaultSmtpRequest(SmtpCommand command, List<CharSequence> parameters) {
+         this.command = ObjectUtil.checkNotNull(command, "command");
++        SmtpUtils.validateSMTPParameters(parameters);
+         this.parameters = parameters != null ?
+                 Collections.unmodifiableList(parameters) : Collections.<CharSequence>emptyList();
+     }
+diff --git a/codec-smtp/src/main/java/io/netty/handler/codec/smtp/SmtpUtils.java b/codec-smtp/src/main/java/io/netty/handler/codec/smtp/SmtpUtils.java
+index a2b84ea..6b84dc1 100644
+--- a/codec-smtp/src/main/java/io/netty/handler/codec/smtp/SmtpUtils.java
++++ b/codec-smtp/src/main/java/io/netty/handler/codec/smtp/SmtpUtils.java
+@@ -28,5 +28,49 @@ final class SmtpUtils {
+         return Collections.unmodifiableList(Arrays.asList(sequences));
+     }
+ 
++    /**
++     * Validates SMTP parameters to prevent SMTP command injection.
++     * Throws IllegalArgumentException if any parameter contains CRLF sequences.
++     */
++    static void validateSMTPParameters(CharSequence... parameters) {
++        if (parameters != null) {
++            for (CharSequence parameter : parameters) {
++                if (parameter != null) {
++                    validateSMTPParameter(parameter);
++                }
++            }
++        }
++    }
++
++    /**
++     * Validates SMTP parameters to prevent SMTP command injection.
++     * Throws IllegalArgumentException if any parameter contains CRLF sequences.
++     */
++    static void validateSMTPParameters(List<CharSequence> parameters) {
++        if (parameters != null) {
++            for (CharSequence parameter : parameters) {
++                if (parameter != null) {
++                    validateSMTPParameter(parameter);
++                }
++            }
++        }
++    }
++
++    private static void validateSMTPParameter(CharSequence parameter) {
++        if (parameter instanceof String) {
++            String paramStr = (String) parameter;
++            if (paramStr.indexOf('\r') != -1 || paramStr.indexOf('\n') != -1) {
++                throw new IllegalArgumentException("SMTP parameter contains CRLF characters: " + parameter);
++            }
++        } else {
++            for (int i = 0; i < parameter.length(); i++) {
++                char c = parameter.charAt(i);
++                if (c == '\r' || c == '\n') {
++                    throw new IllegalArgumentException("SMTP parameter contains CRLF characters: " + parameter);
++                }
++            }
++        }
++    }
++
+     private SmtpUtils() { }
+ }
+diff --git a/codec-smtp/src/test/java/io/netty/handler/codec/smtp/SmtpRequestsTest.java b/codec-smtp/src/test/java/io/netty/handler/codec/smtp/SmtpRequestsTest.java
+new file mode 100644
+index 0000000..f7b5b6a
+--- /dev/null
++++ b/codec-smtp/src/test/java/io/netty/handler/codec/smtp/SmtpRequestsTest.java
+@@ -0,0 +1,73 @@
++/*
++ * Copyright 2025 The Netty Project
++ *
++ * The Netty Project licenses this file to you under the Apache License,
++ * version 2.0 (the "License"); you may not use this file except in compliance
++ * with the License. You may obtain a copy of the License at:
++ *
++ *   https://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
++ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
++ * License for the specific language governing permissions and limitations
++ * under the License.
++ */
++package io.netty.handler.codec.smtp;
++
++import org.junit.jupiter.api.Test;
++import org.junit.jupiter.api.function.Executable;
++
++import static org.junit.jupiter.api.Assertions.assertThrows;
++
++public class SmtpRequestsTest {
++    @Test
++    public void testSmtpInjectionWithCarriageReturn() {
++        assertThrows(IllegalArgumentException.class, new Executable() {
++            @Override
++            public void execute() {
++                SmtpRequests.mail("test at example.com\rQUIT");
++            }
++        });
++    }
++
++    @Test
++    public void testSmtpInjectionWithLineFeed() {
++        assertThrows(IllegalArgumentException.class, new Executable() {
++            @Override
++            public void execute() {
++                SmtpRequests.mail("test at example.com\nQUIT");
++            }
++        });
++    }
++
++    @Test
++    public void testSmtpInjectionWithCRLF() {
++        assertThrows(IllegalArgumentException.class, new Executable() {
++            @Override
++            public void execute() {
++                SmtpRequests.rcpt("test at example.com\r\nQUIT");
++            }
++        });
++    }
++
++    @Test
++    public void testSmtpInjectionInAuthParameter() {
++        assertThrows(IllegalArgumentException.class, new Executable() {
++            @Override
++            public void execute() {
++                SmtpRequests.auth("PLAIN", "dGVzdA\rQUIT");
++            }
++        });
++    }
++
++    @Test
++    public void testSmtpInjectionInHelo() {
++        assertThrows(IllegalArgumentException.class, new Executable() {
++            @Override
++            public void execute() {
++                SmtpRequests.helo("localhost\r\nQUIT");
++            }
++        });
++    }
++}


=====================================
debian/patches/series
=====================================
@@ -23,3 +23,8 @@ CVE-2022-41881.patch
 CVE-2022-41915.patch
 CVE-2023-34462.patch
 CVE-2023-44487.patch
+CVE-2025-59419
+CVE-2025-55163_before-1.patch
+CVE-2025-55163_1.patch
+CVE-2025-55163_2.patch
+CVE-2025-58056.patch


=====================================
debian/salsa-ci.yml
=====================================
@@ -0,0 +1,12 @@
+---
+include:
+  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/recipes/debian.yml
+
+variables:
+  RELEASE: 'bookworm'
+  # disable irrelevant jobs as this package only builds arch:all
+  SALSA_CI_DISABLE_BLHC: 1
+  SALSA_CI_DISABLE_BUILD_PACKAGE_I386: 1
+  SALSA_CI_DISABLE_CROSSBUILD_ARM64: 1
+  SALSA_CI_DISABLE_BUILD_PACKAGE_ALL: 1
+  SALSA_CI_DISABLE_BUILD_PACKAGE_ANY: 1



View it on GitLab: https://salsa.debian.org/java-team/netty/-/compare/863a6492a0a8eda63b6e7022ba4914301afb9e80...3571b5bdbaf4b9df12ecb6a95482d69c627b5864

-- 
View it on GitLab: https://salsa.debian.org/java-team/netty/-/compare/863a6492a0a8eda63b6e7022ba4914301afb9e80...3571b5bdbaf4b9df12ecb6a95482d69c627b5864
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/20251115/19e28157/attachment.htm>


More information about the pkg-java-commits mailing list