Skip to content

Commit

Permalink
Check for newlines in email address. (#102311)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

* Remove compat switch

---------

Co-authored-by: Tomas Weinfurt <[email protected]>
Co-authored-by: Miha Zupan <[email protected]>
  • Loading branch information
3 people authored May 20, 2024
1 parent 5f067ce commit 8fcadc6
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public override bool IsValid(object? value)
return false;
}

if (valueAsString.AsSpan().ContainsAny('\r', '\n'))
{
return false;
}

// only return true if there is only 1 '@' character
// and it is neither the first nor the last character
int index = valueAsString.IndexOf('@');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ protected override IEnumerable<TestCase> InvalidValues()
yield return new TestCase(new EmailAddressAttribute(), 0);
yield return new TestCase(new EmailAddressAttribute(), "");
yield return new TestCase(new EmailAddressAttribute(), " \r \t \n" );
yield return new TestCase(new EmailAddressAttribute(), "someName@[\r\n\tsomeDomain]");
yield return new TestCase(new EmailAddressAttribute(), "@someDomain.com");
yield return new TestCase(new EmailAddressAttribute(), "@[email protected]");
yield return new TestCase(new EmailAddressAttribute(), "someName");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,12 @@ private string GetHost(bool allowUnicode)
throw new SmtpException(SR.Format(SR.SmtpInvalidHostName, Address), argEx);
}
}

if (domain.AsSpan().ContainsAny('\r', '\n'))
{
throw new SmtpException(SR.Format(SR.SmtpInvalidHostName, Address));
}

return domain;
}

Expand Down
40 changes: 40 additions & 0 deletions src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@
// (C) 2006 John Luke
//

using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.DotNet.RemoteExecutor;
using Systen.Net.Mail.Tests;
using System.Net.Test.Common;
using Xunit;
Expand Down Expand Up @@ -573,5 +577,41 @@ public void TestGssapiAuthentication()

Assert.Equal("GSSAPI", server.AuthMethodUsed, StringComparer.OrdinalIgnoreCase);
}

[Theory]
[MemberData(nameof(SendMail_MultiLineDomainLiterals_Data))]
public async Task SendMail_MultiLineDomainLiterals_Disabled_Throws(string from, string to, bool asyncSend)
{
using var server = new LoopbackSmtpServer();

using SmtpClient client = server.CreateClient();
client.Credentials = new NetworkCredential("Foo", "Bar");

using var msg = new MailMessage(@from, @to, "subject", "body");

await Assert.ThrowsAsync<SmtpException>(async () =>
{
if (asyncSend)
{
await client.SendMailAsync(msg).WaitAsync(TimeSpan.FromSeconds(30));
}
else
{
client.Send(msg);
}
});
}

public static IEnumerable<object[]> SendMail_MultiLineDomainLiterals_Data()
{
foreach (bool async in new[] { true, false })
{
foreach (string address in new[] { "foo@[\r\n bar]", "foo@[bar\r\n ]", "foo@[bar\r\n baz]" })
{
yield return new object[] { address, "[email protected]", async };
yield return new object[] { "[email protected]", address, async };
}
}
}
}
}

0 comments on commit 8fcadc6

Please sign in to comment.