Skip to content

Commit 1782e8c

Browse files
DepthFirstDisclosuresnormanmaurerchrisvest
authored
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>
1 parent e4632f5 commit 1782e8c

3 files changed

Lines changed: 119 additions & 0 deletions

File tree

codec-smtp/src/main/java/io/netty/handler/codec/smtp/DefaultSmtpRequest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public DefaultSmtpRequest(SmtpCommand command) {
4343
*/
4444
public DefaultSmtpRequest(SmtpCommand command, CharSequence... parameters) {
4545
this.command = ObjectUtil.checkNotNull(command, "command");
46+
SmtpUtils.validateSMTPParameters(parameters);
4647
this.parameters = SmtpUtils.toUnmodifiableList(parameters);
4748
}
4849

@@ -55,6 +56,7 @@ public DefaultSmtpRequest(CharSequence command, CharSequence... parameters) {
5556

5657
DefaultSmtpRequest(SmtpCommand command, List<CharSequence> parameters) {
5758
this.command = ObjectUtil.checkNotNull(command, "command");
59+
SmtpUtils.validateSMTPParameters(parameters);
5860
this.parameters = parameters != null ?
5961
Collections.unmodifiableList(parameters) : Collections.<CharSequence>emptyList();
6062
}

codec-smtp/src/main/java/io/netty/handler/codec/smtp/SmtpUtils.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,49 @@ static List<CharSequence> toUnmodifiableList(CharSequence... sequences) {
2828
return Collections.unmodifiableList(Arrays.asList(sequences));
2929
}
3030

31+
/**
32+
* Validates SMTP parameters to prevent SMTP command injection.
33+
* Throws IllegalArgumentException if any parameter contains CRLF sequences.
34+
*/
35+
static void validateSMTPParameters(CharSequence... parameters) {
36+
if (parameters != null) {
37+
for (CharSequence parameter : parameters) {
38+
if (parameter != null) {
39+
validateSMTPParameter(parameter);
40+
}
41+
}
42+
}
43+
}
44+
45+
/**
46+
* Validates SMTP parameters to prevent SMTP command injection.
47+
* Throws IllegalArgumentException if any parameter contains CRLF sequences.
48+
*/
49+
static void validateSMTPParameters(List<CharSequence> parameters) {
50+
if (parameters != null) {
51+
for (CharSequence parameter : parameters) {
52+
if (parameter != null) {
53+
validateSMTPParameter(parameter);
54+
}
55+
}
56+
}
57+
}
58+
59+
private static void validateSMTPParameter(CharSequence parameter) {
60+
if (parameter instanceof String) {
61+
String paramStr = (String) parameter;
62+
if (paramStr.indexOf('\r') != -1 || paramStr.indexOf('\n') != -1) {
63+
throw new IllegalArgumentException("SMTP parameter contains CRLF characters: " + parameter);
64+
}
65+
} else {
66+
for (int i = 0; i < parameter.length(); i++) {
67+
char c = parameter.charAt(i);
68+
if (c == '\r' || c == '\n') {
69+
throw new IllegalArgumentException("SMTP parameter contains CRLF characters: " + parameter);
70+
}
71+
}
72+
}
73+
}
74+
3175
private SmtpUtils() { }
3276
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2025 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.handler.codec.smtp;
17+
18+
import org.junit.jupiter.api.Test;
19+
import org.junit.jupiter.api.function.Executable;
20+
21+
import static org.junit.jupiter.api.Assertions.assertThrows;
22+
23+
public class SmtpRequestsTest {
24+
@Test
25+
public void testSmtpInjectionWithCarriageReturn() {
26+
assertThrows(IllegalArgumentException.class, new Executable() {
27+
@Override
28+
public void execute() {
29+
SmtpRequests.mail("test@example.com\rQUIT");
30+
}
31+
});
32+
}
33+
34+
@Test
35+
public void testSmtpInjectionWithLineFeed() {
36+
assertThrows(IllegalArgumentException.class, new Executable() {
37+
@Override
38+
public void execute() {
39+
SmtpRequests.mail("test@example.com\nQUIT");
40+
}
41+
});
42+
}
43+
44+
@Test
45+
public void testSmtpInjectionWithCRLF() {
46+
assertThrows(IllegalArgumentException.class, new Executable() {
47+
@Override
48+
public void execute() {
49+
SmtpRequests.rcpt("test@example.com\r\nQUIT");
50+
}
51+
});
52+
}
53+
54+
@Test
55+
public void testSmtpInjectionInAuthParameter() {
56+
assertThrows(IllegalArgumentException.class, new Executable() {
57+
@Override
58+
public void execute() {
59+
SmtpRequests.auth("PLAIN", "dGVzdA\rQUIT");
60+
}
61+
});
62+
}
63+
64+
@Test
65+
public void testSmtpInjectionInHelo() {
66+
assertThrows(IllegalArgumentException.class, new Executable() {
67+
@Override
68+
public void execute() {
69+
SmtpRequests.helo("localhost\r\nQUIT");
70+
}
71+
});
72+
}
73+
}

0 commit comments

Comments
 (0)