ASVS 5.0 V4.2.1 (level 2) requires every component that handles your traffic, load balancers, firewalls and application servers, to work out where an HTTP message ends using the right rule for the HTTP version. In HTTP/1.x, if Transfer-Encoding is present, Content-Length must be ignored. In HTTP/2 and HTTP/3, a Content-Length header, if present, must match the length of the DATA frames.
The goal is to stop request smuggling, where the front end and back end disagree about message boundaries.
Why it matters
If a proxy thinks a request ends at byte 100 and the backend thinks it ends at byte 60, the leftover 40 bytes become the start of the next request on that shared connection. An attacker uses that to poison another user's request, bypass front end access controls or steal responses. See CWE-444.
The danger is the mix of components. Each one may be fine alone. The bug lives in the disagreement, often when HTTP/2 at the edge is downgraded to HTTP/1.1 behind it.
How to implement it
Most of the fix is configuration and keeping software current.
- Use maintained versions of your proxy, CDN and application server. Many smuggling bugs were fixed in parsers years ago.
- Prefer HTTP/2 or HTTP/3 end to end. If the edge downgrades to HTTP/1.1, make sure it rebuilds the message instead of passing raw headers.
- Reject ambiguous requests at the edge, such as ones with both Transfer-Encoding and Content-Length, duplicate Content-Length values, or obfuscated header names.
- Disable connection reuse between proxy and backend if you cannot trust the backend parser.
A typical hardening on a Node server:
const server = http.createServer({ insecureHTTPParser: false }, app);
server.headersTimeout = 15000;
Keep insecureHTTPParser off, since turning it on relaxes the rules that block malformed framing.
How to test it
Use a scanner built for smuggling, such as the HTTP Request Smuggler extension for Burp Suite, against your real production topology rather than one server alone. Manually, you can send a request with both headers and watch the response.
printf 'POST / HTTP/1.1\r\nHost: example.com\r\nContent-Length: 6\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\nX' | openssl s_client -quiet -connect example.com:443
A safe edge rejects it with a 400 or closes the connection. Test each hop pair separately: CDN to load balancer, load balancer to app.
Common mistakes
- Testing only the app server and not the full chain.
- Assuming HTTP/2 at the edge makes you immune while the backend still speaks HTTP/1.1.
- Running old proxy versions because nothing is visibly broken.
- Enabling lenient parsing flags to make a strange client work.
- Keeping long lived shared connections between proxy and backend without validating framing.
Quick check
In HTTP/1.1, what must a server do if a request has both Transfer-Encoding and Content-Length?
Use Transfer-Encoding and ignore Content-Length. Better still, reject the ambiguous request at the edge.
Sources
- OWASP Application Security Verification Standard, requirement V4.2.1 (level 2)
- RFC 9112, HTTP/1.1 message body length
- RFC 9113, HTTP/2