From: DepthFirst Disclosures <disclosures@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@apple.com>

---------

Co-authored-by: Norman Maurer <norman_maurer@apple.com>
Co-authored-by: Chris Vest <christianvest_hansen@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

--- 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 DefaultSmtpRequest(SmtpCommand command, CharSequence... parameters) {
         this.command = ObjectUtil.checkNotNull(command, "command");
+        SmtpUtils.validateSMTPParameters(parameters);
         this.parameters = SmtpUtils.toUnmodifiableList(parameters);
     }
 
@@ -55,6 +56,7 @@
 
     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();
     }
--- 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 @@
         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() { }
 }
--- /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@example.com\rQUIT");
+            }
+        });
+    }
+
+    @Test
+    public void testSmtpInjectionWithLineFeed() {
+        assertThrows(IllegalArgumentException.class, new Executable() {
+            @Override
+            public void execute() {
+                SmtpRequests.mail("test@example.com\nQUIT");
+            }
+        });
+    }
+
+    @Test
+    public void testSmtpInjectionWithCRLF() {
+        assertThrows(IllegalArgumentException.class, new Executable() {
+            @Override
+            public void execute() {
+                SmtpRequests.rcpt("test@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");
+            }
+        });
+    }
+}
