ContentType.Boundary accepts CRLF allowing MIME structure injection via MimeWriter
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
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
1. **`ContentType.Boundary` setter** (`ContentType.cs:55-68`) — No CRLF validation:
```csharp
public string? Boundary
{
set
{
_parameters ??= new StringDictionary();
_parameters["boundary"] = value;
_isChanged = true;
}
}
```
2. **`MimeWriter` constructor** (`MimeWriter.cs:25`) — Converts boundary to raw ASCII bytes, preserving CRLF:
```csharp
_boundaryBytes = Encoding.ASCII.GetBytes(boundary);
```
3. **`MimeWriter.CheckBoundary()`** (`MimeWriter.cs:70-79`) — Writes raw boundary bytes into MIME body:
```csharp
_bufferBuilder.Append("\r\n--"u8);
_bufferBuilder.Append(_boundaryBytes); // Contains injected CRLF!
_bufferBuilder.Append("\r\n"u8);
```
4. **`MimeMultiPart.SendAsync()`** (`MimeMultiPart.cs:48`) — Passes raw `ContentType.Boundary` to MimeWriter:
```csharp
MimeWriter mimeWriter = new MimeWriter(outputStream, ContentType.Boundary!);
```
## Repro
```csharp
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
INJECTED
";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
INJECTED
"--legit
Content-Type: text/html ← INJECTED HEADER
INJECTED
← INJECTED CONTENTContent-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`:
```csharp
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
- **#128981**: Validates `ContentType.Name` and `ContentDisposition.FileName` against header injection (different attack vector — parameter injection via crafted RFC 2047 encoded-words, not CRLF in boundary)
- **CVE-2026-32178**: CRLF injection in `MailAddress` display 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.
Contributor guide
Research direction
Start with the ContentType.Boundary setter in ContentType.cs and trace how its value reaches the MimeWriter constructor and CheckBoundary(), via MimeMultiPart.SendAsync(). Add validation so CR and LF cannot reach the raw MIME boundary bytes, then verify that such boundary values are rejected and normal MIME serialization remains unaffected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- security
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100