Prevent corrupted SMTP headers when MailAddress.DisplayName contains CR/LF#128980
Conversation
…TP headers Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
|
Tagging subscribers to this area: @karelz, @dotnet/ncl |
…edDisplayName flag Co-authored-by: mrek-msft <188900745+mrek-msft@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR hardens System.Net.Mail against CR/LF injection/corruption via MailAddress.DisplayName, preventing malformed From:/To: header output when addresses are serialized for SMTP.
Changes:
- Add CR/LF rejection for caller-supplied
displayNameinMailAddress.TryParse(throwing for constructors;TryCreatereturnsfalse). - Strip CR/LF from display names parsed out of the full
addressstring (unfolding) via a newStripCRLFhelper. - Add unit tests covering CR, LF, and CRLF in caller-supplied display names for both
MailAddressconstructors andTryCreate.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs | Reject CR/LF in caller-supplied display names; strip CR/LF from parsed display names to avoid header corruption. |
| src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressDisplayNameTest.cs | Add unit tests asserting CR/LF in caller-supplied display names throws / fails TryCreate. |
| @@ -158,13 +172,34 @@ private static bool TryParse([NotNullWhen(true)] string? address, string? displa | |||
| if (string.IsNullOrEmpty(displayName)) | |||
| { | |||
| displayName = info.DisplayName; | |||
|
|
|||
| // The display name parsed out of 'address' may contain folding white space | |||
| // (CRLF inside a quoted string, RFC 5322 §3.2.4). Unfold by stripping any | |||
| // CR/LF characters so re-encoding into a header does not corrupt the output. | |||
| if (!string.IsNullOrEmpty(displayName) && MailBnfHelper.HasCROrLF(displayName)) | |||
| { | |||
There was a problem hiding this comment.
Addressed in f12da96. The branch now aligns with #130175 by rejecting CR/LF at the parser level for address strings (covering ParseMultipleAddresses/MailAddressCollection.Add and MailMessage construction), while keeping the separate rejection for caller-supplied displayName. I also removed the earlier unfold path and updated the affected unit/functional tests accordingly.
| [Theory] | ||
| [InlineData("Display\rName")] | ||
| [InlineData("Display\nName")] | ||
| [InlineData("Display\r\nName")] | ||
| [InlineData("DisplayName\r")] | ||
| [InlineData("DisplayName\n")] | ||
| [InlineData("DisplayName\r\n")] | ||
| [InlineData("\rDisplayName")] | ||
| [InlineData("\nDisplayName")] | ||
| [InlineData("\"Display\r\nName\"")] | ||
| public void MailAddress_Ctor_DisplayNameContainsCRLF_Throws(string displayName) | ||
| { | ||
| Assert.Throws<FormatException>(() => new MailAddress(Address, displayName)); | ||
| Assert.False(MailAddress.TryCreate(Address, displayName, out _)); | ||
| } | ||
| } |
Co-authored-by: mrek-msft <188900745+mrek-msft@users.noreply.github.com>
Co-authored-by: mrek-msft <188900745+mrek-msft@users.noreply.github.com>
Co-authored-by: mrek-msft <188900745+mrek-msft@users.noreply.github.com>
MailAddressaccepted display names containing\r/\nandSmtpClientembedded them verbatim intoFrom:/To:headers, breaking header structure and SMTP framing. Typical source: a trailing newline left over from parsing upstream input.Changes in
MailAddress.TryParse(src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs):FormatException, matching the existing convention forMailMessage.Subject(MailBnfHelper.HasCROrLF→MailSubjectInvalidFormat).TryCreatereturnsfalse.addressstring: unfold per RFC 5322 §3.2.4 by stripping CR/LF from the stored value. This preserves the previously-accepted folded input"display \r\n name" <"folding"@domain.com>while ensuring re-encoding produces a clean header.StripCRLFhelper (guarded by anHasCROrLFpre-check, so allocation only occurs when needed).Test coverage added in
MailAddressDisplayNameTest.MailAddress_Ctor_DisplayNameContainsCRLF_Throwsfor CR, LF, and CRLF in leading/middle/trailing positions and inside bounding quotes, against both the constructor andTryCreate.