Every .NET developer has done it: taken a string from user input, passed it to new MailAddress(), and moved on. It works, the email sends, and nobody thinks twice about it. Until a carriage return slips through and your application starts blind-copying every outbound message to an attacker's inbox.
Microsoft's April 2026 servicing update, released on 14 April, patches two high-severity vulnerabilities that affect every supported .NET version — 8, 9, and 10. The first lets attackers inject arbitrary SMTP headers through System.Net.Mail. The second crashes your entire process with an uncatchable StackOverflowException triggered by deeply nested XML sent to System.Security.Cryptography.Xml. Both score 7.5 on the CVSS scale. Both require zero authentication. Both are exploitable over the network with no user interaction.
Here is what they do, how they work, and what you need to change.
CVE-2026-32178: SMTP Header Injection via System.Net.Mail
This is a classic CRLF injection — the kind of bug that has plagued email systems since the early days of SMTP. The MailAddressParser.TryParseAddress method accepted carriage return (\r) and line feed (\n) characters in display names and email addresses without validation. When SmtpClient.Send() serialised a MailMessage, it faithfully wrote those control characters to the TCP stream. The receiving mail server interpreted them as header boundaries.
SMTP, as defined in RFC 5321, uses CRLF (\r\n) sequences to delimit headers. If an attacker can inject those characters into a value that ends up in a mail header, they control the structure of the email.
The attack in practice
Consider a contact form where the user provides their name and email address:
[HttpPost]
public IActionResult SendMessage(ContactForm form)
{
// Bad — user input flows directly into MailAddress
var from = new MailAddress(form.Email, form.Name);
var message = new MailMessage(from, _supportAddress)
{
Subject = form.Subject,
Body = form.Body
};
_smtpClient.Send(message);
return Ok();
}
An attacker submits a name like "Legitimate User\r\nBcc: [email protected]". The MailAddress constructor accepts it without complaint. When the message is serialised and transmitted, the receiving mail server sees a valid Bcc header and silently forwards a copy to the attacker.
The implications extend beyond blind carbon copies. An attacker could inject Reply-To headers to redirect responses, Subject headers to override the original, or even raw SMTP commands if the receiving server is lenient — turning your application into a relay for targeted phishing campaigns.
What the patch does
The parser now calls MailBnfHelper.HasCROrLF() on address components and throws a FormatException if control characters are present:
if (MailBnfHelper.HasCROrLF(data))
{
throw new FormatException(SR.MailAddressInvalidFormat);
}
After patching, any attempt to construct a MailAddress with embedded CRLF characters fails at parse time, before the data reaches a socket.
Defence in depth
Even on the patched runtime, you should validate user input before it reaches email construction. Reject rather than strip — removing control characters silently can mask attack attempts and makes incident investigation harder:
public static class EmailInputValidator
{
private static readonly Regex CrlfPattern = new(@"[\r\n]", RegexOptions.Compiled);
public static string RejectIfContainsCrlf(string input, string paramName)
{
if (CrlfPattern.IsMatch(input))
{
throw new ArgumentException(
"Input contains invalid control characters.", paramName);
}
return input;
}
}
var sanitisedName = EmailInputValidator.RejectIfContainsCrlf(form.Name, nameof(form.Name));
var sanitisedEmail = EmailInputValidator.RejectIfContainsCrlf(form.Email, nameof(form.Email));
var from = new MailAddress(sanitisedEmail, sanitisedName);
// TIP
SmtpClient has been marked obsolete since .NET 6. If you are still using it, this is a good prompt to migrate to a maintained library like MailKit, which has had CRLF injection protections for years. But even if you do not send emails, any code that constructs MailAddress objects for validation or display is affected — the vulnerability is in the parser, not just the transport.
CVE-2026-32203: XML Recursion Bomb in Cryptography.Xml
The second vulnerability targets System.Security.Cryptography.Xml, the library that handles XML digital signatures and encryption. Its LoadXml method processes child elements like <KeyInfo>, <EncryptionMethod>, and <CipherData> recursively. Before this patch, there was no depth limit.
How the attack works
An attacker crafts a syntactically valid XML document containing thousands of nested <EncryptedData> and <EncryptedKey> elements within the http://www.w3.org/2001/04/xmlenc# namespace:
<EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<!-- ...thousands of levels deep... -->
</EncryptedKey>
</KeyInfo>
</EncryptedKey>
</KeyInfo>
</EncryptedData>
When your application calls EncryptedXml.DecryptDocument() or processes signed XML containing this structure, LoadXml recurses into each nested element. With a default thread stack size of 1.5-8 MB, a few thousand levels exhaust the stack.
The result is a StackOverflowException. Unlike most exceptions in .NET, this one cannot be caught. No catch block, no graceful shutdown, no logging. The process terminates immediately and every in-flight request dies with it.
// WARNING
This is not theoretical. Any endpoint that accepts XML and processes it through System.Security.Cryptography.Xml is vulnerable. SOAP APIs, SAML authentication flows, and file upload handlers that verify XML signatures are common targets.
What the patch does
The fix adds a thread-static depth counter:
[ThreadStatic]
private static int t_depth;
public void LoadXml(XmlElement value)
{
try
{
t_depth++;
if (t_depth > DangerousMaxRecursionDepth)
{
throw new CryptographicException(
"The XML element has exceeded the maximum nesting depth allowed.");
}
ParseChildNodes(value);
}
finally
{
t_depth--;
}
}
The default limit is 64 levels — well above any legitimate nesting depth for XML encryption structures. The exception thrown is a standard CryptographicException: catchable, loggable, and non-fatal.
The limit is configurable via the System.Security.Cryptography.Xml.DangerousMaxRecursionDepth AppContext switch. The name includes "Dangerous" for a reason — increasing it re-exposes your application to stack exhaustion.
// IMPORTANT
The default depth of 64 is sufficient for all standard XML encryption use cases. If you think you need more, verify that the XML structure you are processing is not itself a sign of a design problem.
Affected versions and how to patch
Both vulnerabilities affect every supported .NET version across all platforms and architectures:
| Runtime | Vulnerable | Patched |
|---|---|---|
| .NET 10 | 10.0.0 - 10.0.5 | 10.0.6 |
| .NET 9 | 9.0.0 - 9.0.14 | 9.0.15 |
| .NET 8 | 8.0.0 - 8.0.25 | 8.0.26 |
Visual Studio users should update to 17.12.19 or 17.14.30.
Check your current runtime version:
dotnet --list-runtimes
For framework-dependent deployments, updating the runtime on the host machine is sufficient. For self-contained applications, you must recompile against the patched SDK and redeploy — the runtime is bundled inside the published output.
// NOTE
.NET 6 and 7 are out of support and will not receive patches for these vulnerabilities. If you are still running those versions, this is yet another reason to upgrade.
Checking your exposure
Before you dismiss these as irrelevant to your application, check whether the affected APIs are in your dependency tree.
Search for System.Net.Mail usage — not just SmtpClient, but any MailAddress construction:
dotnet list package --include-transitive | grep -i "System.Net.Mail"
grep -r "MailAddress\|SmtpClient" --include="*.cs" .
For the XML vulnerability, check for System.Security.Cryptography.Xml:
dotnet list package --include-transitive | grep -i "Cryptography.Xml"
grep -r "EncryptedXml\|SignedXml\|XmlDsigC14NTransform" --include="*.cs" .
SAML libraries like Sustainsys.Saml2, ITfoxtec.Identity.Saml2, and ComponentSpace.Saml2 typically depend on these XML cryptography APIs. If your application uses federated authentication with SAML, you are almost certainly exposed.
Common pitfalls
"I don't send emails from my app." You might not use SmtpClient directly, but do you construct MailAddress objects for validation or display? The vulnerability is in the parser, not the transport. Any code path that reaches new MailAddress(userInput) is a potential vector.
"I don't use XML encryption." Check your transitive dependencies. SAML authentication, WCF services, and legacy SOAP integrations often pull in System.Security.Cryptography.Xml without you ever importing the namespace directly.
"I'll just add input validation." Validation is defence in depth, not a substitute for patching. The runtime fix addresses the root cause. Your validation handles edge cases where user input reaches email or XML processing through paths you did not anticipate.
"My self-contained app is isolated." Self-contained deployments bundle the runtime. If you compiled against .NET 10.0.5, your application carries the vulnerability regardless of what is installed on the host. Recompile and redeploy.
"We're on .NET Framework, not modern .NET." The April 2026 cumulative update for .NET Framework also includes security fixes. Check the relevant KB article for your Windows version — this servicing cycle covers both ecosystems.
Summary
- CVE-2026-32178 allows attackers to inject arbitrary SMTP headers through
System.Net.Mailby embedding CRLF characters in display names or addresses. The fix rejects control characters at parse time. - CVE-2026-32203 crashes your process with an uncatchable
StackOverflowExceptionby sending deeply nested XML toSystem.Security.Cryptography.Xml. The fix enforces a default recursion limit of 64. - Both score CVSS 7.5, require no authentication, and are exploitable remotely.
- Patch to .NET 10.0.6, 9.0.15, or 8.0.26. Self-contained applications need recompilation and redeployment.
- Add input validation as defence in depth: reject CRLF in email fields and enforce XML depth limits at your application boundary.
- Check your transitive dependencies — SAML libraries and legacy integrations may expose you to these APIs without your code ever referencing them directly.