Skip to content

Commit 8fcadc6

Browse files
rzikmTomas WeinfurtMihaZupan
authored
Check for newlines in email address. (dotnet#102311)
* Check for newlines in email address. This adds validation for embedded newlines in email addresses. There is opt-in System.Net.Mail.EnableFullDomainLiterals switch to allow previous behavior * Apply suggestions from code review Co-authored-by: Miha Zupan <mihazupan.zupan1@gmail.com> * Remove compat switch --------- Co-authored-by: Tomas Weinfurt <Tomas.Weinfurt@microsoft.com> Co-authored-by: Miha Zupan <mihazupan.zupan1@gmail.com>
1 parent 5f067ce commit 8fcadc6

File tree

4 files changed

+52
-0
lines changed

4 files changed

+52
-0
lines changed

src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/EmailAddressAttribute.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ public override bool IsValid(object? value)
2727
return false;
2828
}
2929

30+
if (valueAsString.AsSpan().ContainsAny('\r', '\n'))
31+
{
32+
return false;
33+
}
34+
3035
// only return true if there is only 1 '@' character
3136
// and it is neither the first nor the last character
3237
int index = valueAsString.IndexOf('@');

src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/EmailAddressAttributeTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ protected override IEnumerable<TestCase> InvalidValues()
2929
yield return new TestCase(new EmailAddressAttribute(), 0);
3030
yield return new TestCase(new EmailAddressAttribute(), "");
3131
yield return new TestCase(new EmailAddressAttribute(), " \r \t \n" );
32+
yield return new TestCase(new EmailAddressAttribute(), "someName@[\r\n\tsomeDomain]");
3233
yield return new TestCase(new EmailAddressAttribute(), "@someDomain.com");
3334
yield return new TestCase(new EmailAddressAttribute(), "@someDomain@abc.com");
3435
yield return new TestCase(new EmailAddressAttribute(), "someName");

src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,12 @@ private string GetHost(bool allowUnicode)
216216
throw new SmtpException(SR.Format(SR.SmtpInvalidHostName, Address), argEx);
217217
}
218218
}
219+
220+
if (domain.AsSpan().ContainsAny('\r', '\n'))
221+
{
222+
throw new SmtpException(SR.Format(SR.SmtpInvalidHostName, Address));
223+
}
224+
219225
return domain;
220226
}
221227

src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@
99
// (C) 2006 John Luke
1010
//
1111

12+
using System.Collections.Generic;
13+
using System.Globalization;
1214
using System.IO;
1315
using System.Net.NetworkInformation;
1416
using System.Net.Sockets;
17+
using System.Reflection;
1518
using System.Threading;
1619
using System.Threading.Tasks;
20+
using Microsoft.DotNet.RemoteExecutor;
1721
using Systen.Net.Mail.Tests;
1822
using System.Net.Test.Common;
1923
using Xunit;
@@ -573,5 +577,41 @@ public void TestGssapiAuthentication()
573577

574578
Assert.Equal("GSSAPI", server.AuthMethodUsed, StringComparer.OrdinalIgnoreCase);
575579
}
580+
581+
[Theory]
582+
[MemberData(nameof(SendMail_MultiLineDomainLiterals_Data))]
583+
public async Task SendMail_MultiLineDomainLiterals_Disabled_Throws(string from, string to, bool asyncSend)
584+
{
585+
using var server = new LoopbackSmtpServer();
586+
587+
using SmtpClient client = server.CreateClient();
588+
client.Credentials = new NetworkCredential("Foo", "Bar");
589+
590+
using var msg = new MailMessage(@from, @to, "subject", "body");
591+
592+
await Assert.ThrowsAsync<SmtpException>(async () =>
593+
{
594+
if (asyncSend)
595+
{
596+
await client.SendMailAsync(msg).WaitAsync(TimeSpan.FromSeconds(30));
597+
}
598+
else
599+
{
600+
client.Send(msg);
601+
}
602+
});
603+
}
604+
605+
public static IEnumerable<object[]> SendMail_MultiLineDomainLiterals_Data()
606+
{
607+
foreach (bool async in new[] { true, false })
608+
{
609+
foreach (string address in new[] { "foo@[\r\n bar]", "foo@[bar\r\n ]", "foo@[bar\r\n baz]" })
610+
{
611+
yield return new object[] { address, "foo@example.com", async };
612+
yield return new object[] { "foo@example.com", address, async };
613+
}
614+
}
615+
}
576616
}
577617
}

0 commit comments

Comments
 (0)