Skip to content

Commit 12aac84

Browse files
committed
#88 Added validation checks for suspicious injection characters. Checking the entire email (except for the DKIM properties)
1 parent 307c182 commit 12aac84

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

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

+44-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.hazlewood.connor.bottema.emailaddress.EmailAddressValidator;
55
import org.simplejavamail.MailException;
66
import org.simplejavamail.converter.internal.mimemessage.MimeMessageHelper;
7+
import org.simplejavamail.email.AttachmentResource;
78
import org.simplejavamail.email.Email;
89
import org.simplejavamail.email.Recipient;
910
import org.simplejavamail.mailer.config.ProxyConfig;
@@ -20,6 +21,7 @@
2021
import javax.mail.Session;
2122
import javax.mail.internet.MimeMessage;
2223
import java.util.EnumSet;
24+
import java.util.Map;
2325
import java.util.Properties;
2426

2527
import static java.lang.String.format;
@@ -341,9 +343,18 @@ public final synchronized void sendMail(final Email email, @SuppressWarnings("Sa
341343
mailSender.send(email, async);
342344
}
343345
}
344-
346+
345347
/**
346348
* Validates an {@link Email} instance. Validation fails if the subject is missing, content is missing, or no recipients are defined.
349+
* <p>
350+
* It also checks for illegal characters that would facilitate injection attacks:
351+
*
352+
* <ul>
353+
* <li>http://www.cakesolutions.net/teamblogs/2008/05/08/email-header-injection-security</li>
354+
* <li>https://security.stackexchange.com/a/54100/110048</li>
355+
* <li>https://www.owasp.org/index.php/Testing_for_IMAP/SMTP_Injection_(OTG-INPVAL-011)</li>
356+
* <li>http://cwe.mitre.org/data/definitions/93.html</li>
357+
* </ul>
347358
*
348359
* @param email The email that needs to be configured correctly.
349360
* @return Always <code>true</code> (throws a {@link MailException} exception if validation fails).
@@ -353,6 +364,28 @@ public final synchronized void sendMail(final Email email, @SuppressWarnings("Sa
353364
@SuppressWarnings({ "SameReturnValue", "WeakerAccess" })
354365
public boolean validate(final Email email)
355366
throws MailException {
367+
// check for illegal values
368+
scanForInjectionAttack(email.getSubject(), "email.subject");
369+
for (Map.Entry<String, String> headerEntry : email.getHeaders().entrySet()) {
370+
scanForInjectionAttack(headerEntry.getKey(), "email.header.mapEntryKey");
371+
scanForInjectionAttack(headerEntry.getValue(), "email.header." + headerEntry.getKey());
372+
}
373+
for (AttachmentResource attachment : email.getAttachments()) {
374+
scanForInjectionAttack(attachment.getName(), "email.attachment.name");
375+
}
376+
for (AttachmentResource embeddedImage : email.getEmbeddedImages()) {
377+
scanForInjectionAttack(embeddedImage.getName(), "email.embeddedImage.name");
378+
}
379+
scanForInjectionAttack(email.getFromRecipient().getName(), "email.fromRecipient.name");
380+
scanForInjectionAttack(email.getFromRecipient().getAddress(), "email.fromRecipient.address");
381+
scanForInjectionAttack(email.getReplyToRecipient().getName(), "email.replyToRecipient.name");
382+
scanForInjectionAttack(email.getReplyToRecipient().getAddress(), "email.replyToRecipient.address");
383+
for (Recipient recipient : email.getRecipients()) {
384+
scanForInjectionAttack(recipient.getName(), "email.recipient.name");
385+
scanForInjectionAttack(recipient.getAddress(), "email.recipient.address");
386+
}
387+
388+
// check for mandatory values
356389
if (email.getText() == null && email.getTextHTML() == null) {
357390
throw new MailerException(MailerException.MISSING_CONTENT);
358391
} else if (email.getSubject() == null || email.getSubject().equals("")) {
@@ -377,6 +410,16 @@ public boolean validate(final Email email)
377410
}
378411
return true;
379412
}
413+
414+
/**
415+
* @param value Value checked for suspicious newline characters "\n", "\r" and "%0A" (as acknowledged by SMTP servers).
416+
* @param valueLabel The name of the field being checked, used for reporting exceptions.
417+
*/
418+
private static void scanForInjectionAttack(String value, String valueLabel) {
419+
if (value != null && (value.contains("\n") || value.contains("\r") || value.contains("%0A"))) {
420+
throw new MailerException(format(MailerException.INJECTION_SUSPECTED, valueLabel, value));
421+
}
422+
}
380423

381424
/**
382425
* Refer to {@link MimeMessageHelper#signMessageWithDKIM(MimeMessage, Email)}

src/main/java/org/simplejavamail/mailer/MailerException.java

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class MailerException extends MailException {
1717
static final String MISSING_RECIPIENT = "Email is not valid: missing recipients";
1818
static final String MISSING_SUBJECT = "Email is not valid: missing subject";
1919
static final String MISSING_CONTENT = "Email is not valid: missing content body";
20+
static final String INJECTION_SUSPECTED = "Suspected of injection attack, field: %s with suspicious value: %s";
2021

2122
MailerException(final String message) {
2223
super(message);

0 commit comments

Comments
 (0)