Crlf Injection in Chi with Mutual Tls
Crlf Injection in Chi with Mutual Tls — how this specific combination creates or exposes the vulnerability
Crlf Injection occurs when an attacker can inject CRLF characters (\r\n) into a header or the body where they are interpreted as delimiters. In Chi, this typically maps to the context.Request.Header and user-controlled inputs that are reflected into headers or chunked output. When Mutual Tls is enforced, the server validates the client certificate, but this does not sanitize or validate the data the authenticated client sends. The presence of Mutual Tls can therefore create a false sense of security, leading developers to skip input validation or header sanitization because they assume only trusted clients can connect.
Chi routes receive a request context; if you bind or forward untrusted input directly into headers or response streams without normalization, an authenticated client (holding a valid certificate) can inject \r\n sequences. For example, reflecting a query parameter such as X-User-ID into a custom header without trimming or encoding gives an authenticated user a way to break header integrity. This can lead to response splitting, cache poisoning, or header smuggling depending on how Chi is deployed behind a proxy or load balancer. Even with Mutual Tls, the application layer remains responsible for canonicalizing and validating all inputs, including those introduced by authenticated TLS clients.
Additionally, logging or error responses in Chi might include user input that contains CRLF characters. If log aggregation tools parse logs line-by-line, injected line breaks can fragment log entries or facilitate log injection. In streaming or chunked transfer scenarios, an attacker can use CRLF to prematurely terminate a chunk and inject crafted lines into the output stream. Therefore, the combination of Mutual Tls and improper handling of untrusted data widens the attack surface by allowing authenticated but malicious clients to manipulate protocol-level boundaries that the framework does not automatically neutralize.
Mutual Tls-Specific Remediation in Chi — concrete code fixes
Remediation focuses on strict input validation and canonicalization, independent of the TLS client verification status. Never assume a valid client certificate implies safe input. In Chi, create request-scoped middleware or filters that sanitize headers and body fields before they are used in routing, logging, or downstream forwarding.
Chi middleware example with Mutual Tls awareness
Below is a complete, minimal Chi setup that enforces Mutual Tls at the listener level and includes sanitization for headers that may contain CRLF sequences. Note that the TLS configuration is handled at the server level; the application code focuses on safe handling of request data.
using Microsoft.AspNetCore.Authentication.Certificate;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Linq;
using System.Text.RegularExpressions;
var builder = WebApplication.CreateBuilder(args);
// Enforce client certificate validation (Mutual Tls)
builder.WebHost.ConfigureKestrel(serverOptions =
{
serverOptions.ListenAnyIP(5001, listenOptions =
{
listenOptions.UseHttps(httpsOptions =
{
ClientCertificateMode = ClientCertificateMode.RequireCertificate,
// Server certificate configured via Kestrel configuration or environment
});
});
});
// Add services if needed
builder.Services.AddHttpClient();
var app = builder.Build();
// CRLF sanitization middleware placed early in the pipeline
app.Use(async (context, next) =
{
// Inspect and sanitize headers that could contain CRLF
var headers = context.Request.Headers;
foreach (var header in headers)
{
if (header.Value.Any(v => v.Contains("\r") || v.Contains("\n")))
{
context.Response.StatusCode = 400;
await context.Response.WriteAsync("Invalid header value");
return;
}
}
// If you read the body for inspection, ensure you do not forward raw CRLF into downstream handlers
// Example: stream copy with filtering omitted for brevity
await next();
});
// A route that reflects a sanitized header
app.MapGet("/hello", (HttpRequest request) =>
{
// Always sanitize before using user-provided values in headers or logs
var userAgent = request.Headers["X-Custom-Header"].ToString();
var safeAgent = SanitizeHeader(userAgent);
request.Headers["X-Custom-Header"] = safeAgent;
return Results.Ok(new { Header = safeAgent });
});
static string SanitizeHeader(string value)
{
if (string.IsNullOrEmpty(value)) return value;
// Remove any CRLF characters; alternatively, reject the request
return value.Replace("\r", string.Empty).Replace("\n", string.Empty);
}
app.Run();
In the above, Mutual Tls ensures that only clients presenting a trusted certificate can reach the endpoint, but the middleware explicitly checks for and rejects header values containing carriage return or line feed characters. This prevents authenticated clients from abusing the request to inject line breaks into headers or logs. The same sanitization should apply to any user-controlled data used in logging, redirect URLs, or chunked output streams.
Chi handler example with bound models
If you bind request data to a model, validate and sanitize properties that may later be reflected into headers or logs. Below is a handler-style route demonstrating validation and safe usage.
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
app.MapPost("/set-user", ([FromBody] UserRequest request) =>
{
// Explicit validation ensures no CRLF in fields that become headers or logs
if (string.IsNullOrEmpty(request.UserId) || request.UserId.Contains("\r") || request.UserId.Contains("\n"))
{
return Results.BadRequest("Invalid UserId");
}
// Safe to use in custom headers or logging
var safeUserId = request.UserId.Replace("\r", string.Empty).Replace("\n", string.Empty);
// Example: setting a response header with sanitized value
Results.Ok().WithHeader("X-User-Id", safeUserId);
return Results.Ok();
});
public class UserRequest
{
[Required]
public string UserId { get; set; }
}
By combining Mutual Tls for transport-layer identity with rigorous input validation and header sanitization at the application layer, you mitigate Crlf Injection risks even when authenticated clients are involved. This approach aligns with secure development practices that treat all inputs as untrusted regardless of the strength of the TLS client authentication.