Request Smuggling in Chi with Mutual Tls
Request Smuggling in Chi with Mutual Tls — how this specific combination creates or exposes the vulnerability
Request smuggling occurs when an intermediary (such as a load balancer or reverse proxy) processes and forwards HTTP requests differently from the backend server. In Chi, enabling Mutual TLS (mTLS) means the server requests client certificates during the TLS handshake, but the application-level request parsing in Chi remains unchanged. This combination does not inherently prevent smuggling; it can inadvertently increase the attack surface when TLS termination happens before the Chi application, and the forwarded request to Chi does not perfectly mirror what the client sent.
With mTLS, the frontend terminates TLS and may normalize or alter headers before forwarding to the Chi backend. If the frontend uses a different header ordering, header case normalization, or strips hop-by-hop headers inconsistently, the request that reaches Chi may differ from what the client intended. Chi routes are typically compiled into a tree based on method and path; if a frontend sends ambiguous content-length and transfer-encoding headers, Chi may parse the request body one way while the frontend interprets it differently. This mismatch can allow an attacker to smuggle a request across security boundaries, such as making a request intended for an authenticated route appear as if it belongs to an unauthenticated route.
Chi routes are built using pattern matchers on method and path, and the framework does not re-parse headers after the TLS layer. If the mTLS frontend forwards requests with inconsistent hop-by-hop header handling (for example, leaving in Transfer-Encoding while also setting Content-Length), Chi may process the body and path differently than the frontend expects. Attackers can exploit this to perform an HTTP request smuggling attack, such as CL.TE or TE.CL variants, to bypass authorization checks or route a request to an unintended endpoint that does not enforce the same mTLS client certificate checks.
Real-world examples include CVE scenarios where a frontend normalizes headers but the backend framework does not, leading to request splitting or cache poisoning. In Chi, if middleware does not strictly normalize and validate headers before routing, an attacker could embed a second request inside the first, causing one request to be interpreted differently by the frontend and the Chi application. This can lead to privilege escalation when a request that should require a client certificate is interpreted as unauthenticated by the route handler due to smuggling-induced path or method confusion.
Because mTLS ensures client identity at the transport layer, developers may assume the request is trustworthy at the application layer. However, smuggling attacks exploit the boundary between transport and application parsing. In Chi, you must ensure that all incoming requests are normalized and validated before they reach the router, regardless of mTLS enforcement, to prevent header inconsistencies from being leveraged for smuggling.
Mutual Tls-Specific Remediation in Chi — concrete code fixes
To mitigate request smuggling in Chi with mTLS, enforce strict header normalization and validation before routing. Ensure that your frontend and backend agree on hop-by-hop header removal and that the request reaching Chi is exactly what the frontend intended. Below are concrete Chi patterns and middleware to reduce risk.
Chi HTTPS server with mTLS (server-side certificate verification)
open System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using var host = Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5001, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
httpsOptions.ServerCertificate = new X509Certificate2("server.pfx", "password");
httpsOptions.ClientCertificateValidation = (cert, chain, errors) =>
{
// Validate client certificate policies (e.g., thumbprint, issuer)
return cert?.Thumbprint == "EXPECTED_CLIENT_THUMBPRINT";
};
});
});
});
webBuilder.UseStartup<Startup>();
})
.Build();
Chi route with strict header normalization middleware
Add a middleware that removes or normalizes hop-by-hop headers before routing. This ensures smuggling attempts that rely on inconsistent header handling are neutralized.
// Program.cs or Startup.cs
app.Use(async (context, next) =>
{
// Remove hop-by-hop headers that should not be forwarded
context.Request.Headers.Remove("Transfer-Encoding");
// Ensure Content-Length is consistent; if Transfer-Encoding is absent, enforce strict parsing
if (context.Request.Headers.ContainsKey("Content-Length"))
{
// Optionally validate Content-Length matches body size
// For smuggling prevention, avoid allowing both headers simultaneously
if (context.Request.Headers.ContainsKey("Transfer-Encoding"))
{
context.Response.StatusCode = 400;
await context.Response.WriteAsync("Invalid hop-by-hop headers");
return;
}
}
await next();
});
app.MapGet("/secure", (HttpRequest req) => $"Client cert subject: {req.HttpContext.Connection.ClientCertificate?.Subject}")
.RequireHttpsConnection();
Frontend forwarding best practices
When a frontend terminates mTLS and forwards to Chi, ensure it:
- Removes
Transfer-Encodingif not needed, and does not send bothContent-LengthandTransfer-Encoding. - Preserves header case and order as required by Chi routing, avoiding case-insensitive merges that hide duplicates.
- Validates the request body size before forwarding to prevent mismatched content-length smuggling.
// Example in a frontend service (pseudo-code)
function forwardToChi(request) {
// Remove hop-by-hop headers
delete request.headers['transfer-encoding'];
// Ensure only one of Content-Length or Transfer-Encoding is present
if (request.body) {
request.headers['content-length'] = Buffer.byteLength(request.body);
}
// Forward with strict header normalization
return httpClient.post('https://chi-backend/secure', request.body, { headers: request.headers });
}
Chi middleware to reject ambiguous requests
Implement a validation step that rejects requests where Content-Length and Transfer-Encoding are both present, as this is a common smuggling indicator.
app.Use((context, next) =>
{
var hasContentLength = context.Request.Headers.ContainsKey("Content-Length");
var hasTransferEncoding = context.Request.Headers.ContainsKey("Transfer-Encoding");
if (hasContentLength && hasTransferEncoding)
{
context.Response.StatusCode = 400;
return context.Response.WriteAsync("Ambiguous headers: Content-Length and Transfer-Encoding cannot both be present");
}
return next();
});
Use schema validation for incoming requests
Use a schema validator to ensure the request path, method, and headers match expected patterns. This reduces parsing ambiguity that smuggling could exploit.
// Example using a simple pattern matcher in Chi
app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/api"), app =>
{
app.Use((context, next) =>
{
// Validate expected route pattern strictly
if (!context.Request.Path.Value.StartsWith("/api/"))
{
context.Response.StatusCode = 404;
return context.Response.WriteAsync("Not found");
}
return next();
});
app.Run((context) => Results.Ok("Authenticated route with mTLS"));
});