Skip to content

Commit 80ec690

Browse files
committedMay 22, 2019
#171: fixed bug where "References" header raised a CRLF Injection flag. Also added test to verify the "References" header is filled properly by replying multiple times in a thread.
1 parent f824285 commit 80ec690

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed
 

‎src/main/java/org/simplejavamail/mailer/Mailer.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import javax.mail.PasswordAuthentication;
2222
import javax.mail.Session;
2323
import javax.mail.internet.MimeMessage;
24+
import javax.mail.internet.MimeUtility;
2425
import java.util.EnumSet;
2526
import java.util.Map;
2627
import java.util.Properties;
@@ -302,7 +303,11 @@ public boolean validate(final Email email)
302303
scanForInjectionAttack(email.getSubject(), "email.subject");
303304
for (final Map.Entry<String, String> headerEntry : email.getHeaders().entrySet()) {
304305
scanForInjectionAttack(headerEntry.getKey(), "email.header.mapEntryKey");
305-
scanForInjectionAttack(headerEntry.getValue(), "email.header." + headerEntry.getKey());
306+
if (headerEntry.getKey().equals("References")) {
307+
scanForInjectionAttack(MimeUtility.unfold(headerEntry.getValue()), "email.header.References");
308+
} else {
309+
scanForInjectionAttack(headerEntry.getValue(), "email.header." + headerEntry.getKey());
310+
}
306311
}
307312
for (final AttachmentResource attachment : email.getAttachments()) {
308313
scanForInjectionAttack(attachment.getName(), "email.attachment.name");
@@ -331,6 +336,11 @@ public boolean validate(final Email email)
331336
/**
332337
* @param value Value checked for suspicious newline characters "\n", "\r" and "%0A" (as acknowledged by SMTP servers).
333338
* @param valueLabel The name of the field being checked, used for reporting exceptions.
339+
*
340+
* @see <a href="http://www.cakesolutions.net/teamblogs/2008/05/08/email-header-injection-security">http://www.cakesolutions.net/teamblogs/2008/05/08/email-header-injection-security</a>
341+
* @see <a href="https://security.stackexchange.com/a/54100/110048">https://security.stackexchange.com/a/54100/110048</a>
342+
* @see <a href="https://www.owasp.org/index.php/Testing_for_IMAP/SMTP_Injection_(OTG-INPVAL-011)">https://www.owasp.org/index.php/Testing_for_IMAP/SMTP_Injection_(OTG-INPVAL-011)</a>
343+
* @see <a href="http://cwe.mitre.org/data/definitions/93.html">http://cwe.mitre.org/data/definitions/93.html</a>
334344
*/
335345
private static void scanForInjectionAttack(final String value, final String valueLabel) {
336346
if (value != null && (value.contains("\n") || value.contains("\r") || value.contains("%0A"))) {

‎src/test/java/org/simplejavamail/mailer/MailerLiveTest.java

+31-7
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717

1818
import javax.mail.MessagingException;
1919
import javax.mail.internet.MimeMessage;
20+
import javax.mail.internet.MimeUtility;
2021
import java.io.IOException;
2122
import java.util.Properties;
2223

24+
import static java.lang.String.format;
2325
import static javax.mail.Message.RecipientType.TO;
2426
import static org.assertj.core.api.Assertions.assertThat;
2527
import static org.assertj.core.data.MapEntry.entry;
@@ -138,7 +140,7 @@ private Email assertSendingEmail(final EmailPopulatingBuilder originalEmailPopul
138140

139141
@Test
140142
public void createMailSession_ReplyToMessage()
141-
throws IOException, MessagingException {
143+
throws MessagingException {
142144
// send initial mail
143145
mailer.sendMail(readOutlookMessage("test-messages/HTML mail with replyto and attachment and embedded image.msg").buildEmail());
144146
MimeMessage receivedMimeMessage = smtpServerRule.getOnlyMessage();
@@ -170,7 +172,7 @@ public void createMailSession_ReplyToMessage()
170172

171173
@Test
172174
public void createMailSession_ReplyToMessage_NotAll_AndCustomReferences()
173-
throws IOException, MessagingException {
175+
throws MessagingException {
174176
// send initial mail
175177
mailer.sendMail(readOutlookMessage("test-messages/HTML mail with replyto and attachment and embedded image.msg").buildEmail());
176178
MimeMessage receivedMimeMessage = smtpServerRule.getOnlyMessage();
@@ -179,20 +181,42 @@ public void createMailSession_ReplyToMessage_NotAll_AndCustomReferences()
179181
// send reply to initial mail
180182
Email reply = EmailBuilder
181183
.replyingTo(assertSendingEmail(receivedEmailPopulatingBuilder, false))
182-
.withHeader("References", "dummy-references")
183-
.from("dummy@domain.com")
184+
.from("Moo Shmoo", "dummy@domain.com")
184185
.withPlainText("This is the reply")
185186
.buildEmail();
186187

187188
// test received reply to initial mail
188189
mailer.sendMail(reply);
189-
MimeMessage receivedMimeMessageReply1 = smtpServerRule.getOnlyMessage("lo.pop.replyto@somemail.com");
190-
Email receivedReply = mimeMessageToEmail(receivedMimeMessageReply1);
190+
MimeMessage receivedMimeMessageReply = smtpServerRule.getOnlyMessage("lo.pop.replyto@somemail.com");
191+
Email receivedReply = mimeMessageToEmail(receivedMimeMessageReply);
191192

192193
EmailAssert.assertThat(receivedReply).hasSubject("Re: hey");
193194
EmailAssert.assertThat(receivedReply).hasOnlyRecipients(new Recipient("lollypop-replyto", "lo.pop.replyto@somemail.com", TO));
194195
assertThat(receivedReply.getHeaders()).contains(entry("In-Reply-To", receivedEmailPopulatingBuilder.getId()));
195-
assertThat(receivedReply.getHeaders()).contains(entry("References", "dummy-references"));
196+
assertThat(receivedReply.getHeaders()).contains(entry("References", receivedEmailPopulatingBuilder.getId()));
197+
198+
EmailPopulatingBuilder receivedEmailReplyPopulatingBuilder = mimeMessageToEmailBuilder(receivedMimeMessageReply);
199+
200+
Email replyToReply = EmailBuilder
201+
.replyingTo(assertSendingEmail(receivedEmailReplyPopulatingBuilder, false))
202+
.from("Pappa Moo", "dummy@domain.com")
203+
.withPlainText("This is the reply to the reply")
204+
.buildEmail();
205+
206+
// test received reply to initial mail
207+
mailer.sendMail(replyToReply);
208+
MimeMessage receivedMimeMessageReplyToReply = smtpServerRule.getOnlyMessage("dummy@domain.com");
209+
Email receivedReplyToReply = mimeMessageToEmail(receivedMimeMessageReplyToReply);
210+
211+
EmailAssert.assertThat(receivedReplyToReply).hasSubject("Re: hey");
212+
EmailAssert.assertThat(receivedReplyToReply).hasOnlyRecipients(new Recipient("Moo Shmoo", "dummy@domain.com", TO));
213+
assertThat(receivedReplyToReply.getHeaders()).contains(entry("In-Reply-To", receivedEmailReplyPopulatingBuilder.getId()));
214+
215+
assertThat(receivedReplyToReply.getHeaders()).contains(entry("References",
216+
MimeUtility.fold("References: ".length(), format("%s\n%s",
217+
receivedEmailPopulatingBuilder.getId(),
218+
receivedEmailReplyPopulatingBuilder.getId()))
219+
));
196220
}
197221

198222
private void assertAttachmentMetadata(AttachmentResource embeddedImg, String mimeType, String filename) {

0 commit comments

Comments
 (0)
Please sign in to comment.