Http Request Smuggling in Express
How Http Request Smuggling Manifests in Express
HTTP request smuggling exploits discrepancies in how a front-end proxy (load balancer, API gateway, or reverse proxy) and the origin server parse HTTP messages. In Express applications, this typically arises when the app is deployed behind a proxy that handles parsing of Transfer-Encoding and Content-Length inconsistently. If Express trusts header values set by the proxy without normalization, an attacker can craft two requests that, when concatenated, are interpreted differently by the proxy and by Express, causing request body leakage or request routing confusion.
Express-specific patterns include:
- CL.TE smuggling: The proxy treats a request with
Transfer-Encoding: chunkedand noContent-Lengthas the end of the message stream, while Express (or a downstream server) reads the next request’s body as part of the current one. Example: a client sendsTransfer-Encoding: chunkedwith a zero-length chunk, then appends a second request in the body. The proxy may forward this as a single stream; Express may parse the second request as part of the first, leading to path or parameter confusion. - TE.CL smuggling: When a proxy removes or ignores
Transfer-Encodingand falls back toContent-Length, Express may read only the bytes specified byContent-Length, leaving the remainder in the buffer for the next request. This can cause authentication bypass or route confusion when the leftover bytes are interpreted as a new request. - In Express, routes like
app.use(bodyParser.json())or custom body parsers that rely onreq.headers['content-length']without normalizing againsttransfer-encodingcan be vulnerable if the proxy normalizes headers before passing them to the app.
Concrete request-smuggling payload targeting an Express stack behind a misconfigured proxy:
POST / HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 50
Transfer-Encoding: chunked
0
POST /admin HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 7
{"test":true}
Here, the proxy may process the first request using Content-Length and stop before the chunked body, while Express (or a backend) reads the chunked stream, causing the second request to be smuggled into the application layer.
Express-Specific Detection
To detect HTTP request smuggling in Express, focus on header normalization and proxy behavior. Key indicators include:
- Inconsistent handling of
Transfer-EncodingandContent-Lengthwhen both are present. - Express routes that directly use
req.headers['content-length']without sanitization, especially when a proxy modifies or strips headers. - Endpoints that accept pipelined or concatenated requests without strict message boundary enforcement.
Using middleBrick, you can scan your Express endpoint to surface these risks. middleBrick runs unauthenticated black-box checks aligned with the OWASP API Top 10 and maps findings to frameworks like PCI-DSS and SOC2. Its LLM/AI Security module tests for prompt injection and output leakage, while the standard security checks identify header-parsing anomalies and BOLA/IDOR patterns that can be exacerbated by smuggling. The scan completes in 5–15 seconds and provides prioritized findings with severity and remediation guidance.
Example CLI usage to include in CI/CD:
middlebrick scan https://api.example.com/v1/openapi.json
Or integrate the GitHub Action to fail builds if the risk score drops below your threshold.
Express-Specific Remediation
Remediation in Express focuses on normalizing headers and avoiding reliance on potentially proxy-modified values. Use built-in middleware that explicitly handles message boundaries and reject ambiguous configurations.
1. Use express.json() and express.urlencoded() with strict parsing:
const express = require('express');
const app = express();
// Explicitly limit JSON body size and reject malformed content
app.use(express.json({ limit: '10kb', strict: true }));
app.use(express.urlencoded({ extended: false, limit: '10kb' }));
Setting strict: true ensures arrays and objects are parsed only in strict mode, reducing ambiguity in body parsing that smuggling attempts can exploit.
2. Reject requests with both Content-Length and Transfer-Encoding:
app.use((req, res, next) => {
const hasTE = req.headers['transfer-encoding'];
const hasCL = req.headers['content-length'];
if (hasTE && hasCL) {
return res.status(400).send('Invalid headers: Content-Length and Transfer-Encoding must not both be present');
}
next();
});
This prevents ambiguous parsing where a proxy might strip one header and forward the other, leaving Express to interpret the message inconsistently.
3. Avoid trusting proxy-set headers for routing or body size decisions. If you must use a proxy, normalize headers before they reach Express:
app.use((req, res, next) => {
// Normalize content-length if a proxy rewrites it incorrectly
if (req.headers['x-forwarded-content-length']) {
req.headers['content-length'] = req.headers['x-forwarded-content-length'];
}
next();
});
Combine this with a strict validation layer that ensures the body size does not exceed expected limits.
4. Use a validated reverse proxy configuration (e.g., Nginx or a cloud load balancer) with explicit Transfer-Encoding handling and no header rewriting that creates mismatches. Ensure the proxy removes or normalizes Transfer-Encoding before forwarding to Express.
These steps reduce the attack surface for request smuggling by enforcing strict message parsing and eliminating header ambiguity that attackers can exploit in Express-based services.