44import org .hazlewood .connor .bottema .emailaddress .EmailAddressValidator ;
55import org .simplejavamail .MailException ;
66import org .simplejavamail .converter .internal .mimemessage .MimeMessageHelper ;
7+ import org .simplejavamail .email .AttachmentResource ;
78import org .simplejavamail .email .Email ;
89import org .simplejavamail .email .Recipient ;
910import org .simplejavamail .mailer .config .ProxyConfig ;
2021import javax .mail .Session ;
2122import javax .mail .internet .MimeMessage ;
2223import java .util .EnumSet ;
24+ import java .util .Map ;
2325import java .util .Properties ;
2426
2527import 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)}
0 commit comments