This is an automated email from the ASF dual-hosted git repository.
quantranhong1999 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-mime4j.git
The following commit(s) were added to refs/heads/master by this push:
new 5616ba58 [ENHANCEMENT] Improve RawField::checkLineBreaks
5616ba58 is described below
commit 5616ba583c7b4191222e2f16bf2cdc7fa08bd2fa
Author: Benoit TELLIER <[email protected]>
AuthorDate: Wed Oct 28 21:50:39 2026 +0100
[ENHANCEMENT] Improve RawField::checkLineBreaks
---
.../org/apache/james/mime4j/stream/RawField.java | 32 +++++++++-----
.../apache/james/mime4j/stream/RawFieldTest.java | 48 +++++++++++++++++++--
.../mime4j/message/DefaultMessageWriterTest.java | 49 +++++++++++++++++++++-
3 files changed, 113 insertions(+), 16 deletions(-)
diff --git a/core/src/main/java/org/apache/james/mime4j/stream/RawField.java
b/core/src/main/java/org/apache/james/mime4j/stream/RawField.java
index 0f7c9dbd..3393a14c 100644
--- a/core/src/main/java/org/apache/james/mime4j/stream/RawField.java
+++ b/core/src/main/java/org/apache/james/mime4j/stream/RawField.java
@@ -57,22 +57,32 @@ public final class RawField implements Field {
public RawField(String name, String body) {
this(null, -1, name, body);
- int pos = 0;
+ if (body != null) {
+ checkLineBreaks(body);
+ }
+ }
- while (true) {
- pos = body.indexOf('\r', pos);
- if (pos < 0) {
- break;
+ /**
+ * Only folds (CRLF followed by SP or HTAB) are allowed: a bare CR, a bare
LF or a CRLF not
+ * followed by whitespace (including at the end of the body) would start a
new header line or
+ * end the header block once written.
+ */
+ private static void checkLineBreaks(String body) {
+ int length = body.length();
+ for (int pos = 0; pos < length; pos++) {
+ char c = body.charAt(pos);
+ if (c == '\n') {
+ throw new IllegalArgumentException("Injection of un-encoded
line breaks inside header field could be assimilated to header injection");
}
- if (pos < body.length() + 2) {
- if (body.charAt(pos + 1) != '\n') {
- throw new IllegalArgumentException("Injection of
un-encoded line breaks inside header field could be assimilated to header
injection");
- }
- if (pos != body.length() - 2 && !isSpace(body, pos + 2)) {
+ if (c == '\r') {
+ if (pos + 2 >= length
+ || body.charAt(pos + 1) != '\n'
+ || !isSpace(body, pos + 2)) {
throw new IllegalArgumentException("Injection of
un-encoded line breaks inside header field could be assimilated to header
injection");
}
+ // Skip the LF of the fold
+ pos++;
}
- pos ++;
}
}
diff --git
a/core/src/test/java/org/apache/james/mime4j/stream/RawFieldTest.java
b/core/src/test/java/org/apache/james/mime4j/stream/RawFieldTest.java
index 775c92dd..49849d08 100644
--- a/core/src/test/java/org/apache/james/mime4j/stream/RawFieldTest.java
+++ b/core/src/test/java/org/apache/james/mime4j/stream/RawFieldTest.java
@@ -80,8 +80,8 @@ public class RawFieldTest {
}
@Test
- public void shouldAcceptCRLFTerminatedHeader() {
- assertThatCode(() -> new RawField("Name",
"Value\r\n")).doesNotThrowAnyException();
+ public void shouldRejectCRLFTerminatedHeader() {
+ assertThatThrownBy(() -> new RawField("Name",
"Value\r\n")).isInstanceOf(IllegalArgumentException.class);
}
@Test
@@ -95,8 +95,48 @@ public class RawFieldTest {
}
@Test
- public void shouldAcceptOnlyDelimiter() {
- assertThatCode(() -> new RawField("Name",
"\r\n")).doesNotThrowAnyException();
+ public void shouldRejectOnlyDelimiter() {
+ assertThatThrownBy(() -> new RawField("Name",
"\r\n")).isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void shouldRejectBareLF() {
+ assertThatThrownBy(() -> new RawField("Name", "x\nBcc:
[email protected]")).isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void shouldRejectBareLFBeforeSpace() {
+ assertThatThrownBy(() -> new RawField("Name", "x\n
y")).isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void shouldRejectOnlyLF() {
+ assertThatThrownBy(() -> new RawField("Name",
"\n\n")).isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void shouldRejectBareCR() {
+ assertThatThrownBy(() -> new RawField("Name", "x\rBcc:
[email protected]")).isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void shouldRejectTrailingCR() {
+ assertThatThrownBy(() -> new RawField("Name",
"Value\r")).isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void shouldRejectCRLFLF() {
+ assertThatThrownBy(() -> new RawField("Name",
"Value\r\n\n")).isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void shouldRejectFoldFollowedByEmptyLine() {
+ assertThatThrownBy(() -> new RawField("Name", "Value\r\n
a\r\n\r\nbody")).isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void shouldAcceptMultipleFolds() {
+ assertThatCode(() -> new RawField("Name", "a\r\n
b\r\n\tc")).doesNotThrowAnyException();
}
diff --git
a/dom/src/test/java/org/apache/james/mime4j/message/DefaultMessageWriterTest.java
b/dom/src/test/java/org/apache/james/mime4j/message/DefaultMessageWriterTest.java
index 19eafe24..9409b801 100644
---
a/dom/src/test/java/org/apache/james/mime4j/message/DefaultMessageWriterTest.java
+++
b/dom/src/test/java/org/apache/james/mime4j/message/DefaultMessageWriterTest.java
@@ -23,7 +23,12 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.apache.james.mime4j.Charsets;
+import java.util.Collections;
+
import org.apache.james.mime4j.dom.Message;
+import org.apache.james.mime4j.dom.address.Mailbox;
+import org.apache.james.mime4j.field.Fields;
+import org.apache.james.mime4j.stream.RawField;
import org.junit.Test;
public class DefaultMessageWriterTest {
@@ -58,4 +63,46 @@ public class DefaultMessageWriterTest {
.isInstanceOf(IllegalArgumentException.class);
}
-}
\ No newline at end of file
+ @Test
+ public void rawFieldShouldRejectBareLF() {
+ assertThatThrownBy(() -> new RawField("X-Custom", "x\nBcc:
[email protected]"))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void rawFieldShouldRejectTrailingCRLF() {
+ assertThatThrownBy(() -> new RawField("X-Custom", "\r\n"))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void messageIdShouldRejectTrailingCRLF() {
+ assertThatThrownBy(() -> Fields.messageId("<a@b>\r\n"))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void messageIdShouldRejectBareLF() {
+ assertThatThrownBy(() -> Fields.messageId("\n\n"))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void fromShouldRejectBareLFInDisplayName() {
+ assertThatThrownBy(() -> Fields.from(new Mailbox("\n!", "", "")))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void contentTypeShouldRejectBareLFInParameter() {
+ assertThatThrownBy(() -> Fields.contentType("text/plain",
Collections.singletonMap("name", "\n")))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void contentDispositionShouldRejectBareLFInFilename() {
+ assertThatThrownBy(() -> Fields.contentDisposition("attachment",
"\n!"))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]