Repository navigation
ContentType.Boundary accepts CRLF allowing MIME structure injection via MimeWriter #131820
Description
Description
ContentType.Boundary accepts CRLF characters (\r\n) without validation. When a user-controlled boundary containing CRLF is used, MimeWriter writes the raw boundary bytes into the MIME body via CheckBoundary(), while the Content-Type header encodes the boundary through GetTokenOrQuotedString(). This mismatch allows injection of arbitrary MIME headers and content into the message body.
Vulnerable Code Path
-
ContentType.Boundarysetter (ContentType.cs:55-68) — No CRLF validation:public string? Boundary { set { _parameters ??= new StringDictionary(); _parameters["boundary"] = value; _isChanged = true; } }
-
MimeWriterconstructor (MimeWriter.cs:25) — Converts boundary to raw ASCII bytes, preserving CRLF:_boundaryBytes = Encoding.ASCII.GetBytes(boundary);
-
MimeWriter.CheckBoundary()(MimeWriter.cs:70-79) — Writes raw boundary bytes into MIME body:_bufferBuilder.Append("\r\n--"u8); _bufferBuilder.Append(_boundaryBytes); // Contains injected CRLF! _bufferBuilder.Append("\r\n"u8);
-
MimeMultiPart.SendAsync()(MimeMultiPart.cs:48) — Passes rawContentType.Boundaryto MimeWriter:MimeWriter mimeWriter = new MimeWriter(outputStream, ContentType.Boundary!);
Repro
using System;
using System.Net.Mail;
using System.Net.Mime;
using System.Text;
var msg = new MailMessage(new MailAddress("from@example.com"), new MailAddress("to@example.com"));
var view = AlternateView.CreateAlternateViewFromString("This is the legitimate content.", Encoding.UTF8);
view.ContentType = new ContentType("text", "plain");
view.ContentType.Boundary = "legit\r\nContent-Type: text/html\r\n\r\n<html><body><h1>INJECTED</h1></body></html>";
msg.AlternateViews.Add(view);
msg.Subject = "Test";
msg.Body = "";
// When serialized (e.g. via SmtpClient or pickup directory), the MIME output contains injected headers.Resulting MIME Output (reconstructed)
Content-Type: multipart/alternative; boundary="legit\r\nContent-Type: text/html\r\n\r\n<html><body><h1>INJECTED</h1></body></html>"
--legit
Content-Type: text/html ← INJECTED HEADER
<html><body><h1>INJECTED</h1></body></html> ← INJECTED CONTENT
Content-Type: text/plain ← Start of legitimate boundary
This is the legitimate content.
--legit--
The Content-Type header correctly encodes the boundary (CRLF is escaped by GetTokenOrQuotedString), but the MIME body uses the raw boundary bytes, creating the mismatch that enables injection.
Impact
- Content injection: Arbitrary HTML/text content injected into email body
- Header injection: Arbitrary MIME headers (Content-Type, Content-Disposition, etc.) injected into the MIME body structure
- Potential XSS: If injected HTML is rendered by email client
- Boundary confusion: Legitimate MIME parts may be misinterpreted or skipped
Suggested Fix
Add CRLF validation to ContentType.Boundary setter, rejecting values containing \r or \n:
public string? Boundary
{
set
{
if (value != null && value.AsSpan().ContainsAny(r, n))
{
throw new ArgumentException("Boundary must not contain CR or LF characters.");
}
_parameters ??= new StringDictionary();
_parameters["boundary"] = value;
_isChanged = true;
}
}Related
- System.Net.Mail Validation improvements #128981: Validates
ContentType.NameandContentDisposition.FileNameagainst header injection (different attack vector — parameter injection via crafted RFC 2047 encoded-words, not CRLF in boundary) - CVE-2026-32178: CRLF injection in
MailAddressdisplay names (patched — address parser, not boundary) - CVE-2026-50659: SMTP dot-stuffing smuggling in
EightBitStream.EncodeLines(patched — different attack surface)
Affected Versions
All supported .NET versions (8, 9, 10) — the ContentType.Boundary setter has never validated for CRLF.
Activity
dotnet-policy-service commentedon Aug 4, 2026
Tagging subscribers to this area: @karelz, @dotnet/ncl
See info in area-owners.md if you want to be subscribed.
dotnet-policy-service commentedon Aug 4, 2026
Tagging subscribers to this area: @karelz, @dotnet/ncl
See info in area-owners.md if you want to be subscribed.
GrabYourPitchforks commentedon Aug 5, 2026
Security review: not a vulnerability. The Boundary property is meant to dictate framing of the data structure, which makes it a control-plane argument rather than a data-plane argument. No trust boundary has been crossed.
EG has discretion as to whether they want to consider this a non-security reliability bug.