diff --git a/libraries/src/Mail/MailHelper.php b/libraries/src/Mail/MailHelper.php index a33011ed98cbc..fcf9d5fa1d26b 100644 --- a/libraries/src/Mail/MailHelper.php +++ b/libraries/src/Mail/MailHelper.php @@ -46,6 +46,11 @@ public static function cleanLine($value) /** * Cleans multi-line inputs. * + * Line breaks directly preceding a mail header name are removed together + * with that header name, so a multi-line value cannot smuggle additional + * headers into the mail. The header names filtered here match the ones + * already covered by cleanBody() and cleanSubject(). + * * @param string $value Multi-line string to be cleaned. * * @return string Cleaned multi-line string. @@ -54,7 +59,7 @@ public static function cleanLine($value) */ public static function cleanText($value) { - return trim(preg_replace('/(%0A|%0D|\n+|\r+)(content-type:|to:|cc:|bcc:)/i', '', $value)); + return trim(preg_replace('/(%0A|%0D|\n+|\r+)+(content-type:|to:|cc:|bcc:|from:|subject:|reply-to:)/i', '', $value)); } /** diff --git a/tests/Unit/Libraries/Cms/Mail/MailHelperTest.php b/tests/Unit/Libraries/Cms/Mail/MailHelperTest.php index f51ac78c25673..2bad636c5731a 100644 --- a/tests/Unit/Libraries/Cms/Mail/MailHelperTest.php +++ b/tests/Unit/Libraries/Cms/Mail/MailHelperTest.php @@ -72,7 +72,8 @@ public function dataCleanText(): array ["test\n\ncontent-type:me", 'testme'], ["test\rcontent-type:me", 'testme'], ["test\r\rcontent-type:me", 'testme'], - // @TODO Should this be included array("test\r\ncoNTent-tYPe:me", 'testme'), + ["test\r\ncoNTent-tYPe:me", 'testme'], + ["test%0A%0DconTenT-Type:me", 'testme'], ["test%0Ato:me", 'testme'], ["test%0DTO:me", 'testme'], @@ -80,7 +81,8 @@ public function dataCleanText(): array ["test\n\ntO:me", 'testme'], ["test\rto:me", 'testme'], ["test\r\rto:me", 'testme'], - // @TODO Should this be included array("test\r\nto:me", 'testme'), + ["test\r\nto:me", 'testme'], + ["test%0A%0DTo:me", 'testme'], ["test%0Acc:me", 'testme'], ["test%0DCC:me", 'testme'], @@ -88,7 +90,7 @@ public function dataCleanText(): array ["test\n\ncC:me", 'testme'], ["test\rcc:me", 'testme'], ["test\r\rcc:me", 'testme'], - // @TODO Should this be included array("test\r\ncc:me", 'testme'), + ["test\r\ncc:me", 'testme'], ["test%0Abcc:me", 'testme'], ["test%0DBCC:me", 'testme'], @@ -96,7 +98,19 @@ public function dataCleanText(): array ["test\n\nbcC:me", 'testme'], ["test\rbcc:me", 'testme'], ["test\r\rbcc:me", 'testme'], - // @TODO Should this be included array("test\r\nbcc:me", 'testme'), + ["test\r\nbcc:me", 'testme'], + + ["test%0Afrom:me", 'testme'], + ["test\r\nFrom:me", 'testme'], + ["test\nfrom:me", 'testme'], + + ["test%0Asubject:me", 'testme'], + ["test\r\nSubject:me", 'testme'], + ["test\nsubject:me", 'testme'], + + ["test%0Areply-to:me", 'testme'], + ["test\r\nReply-To:me", 'testme'], + ["test\nreply-to:me", 'testme'], ]; }