ASVS 5.0 V4.2.2 (level 3) says that when your application generates HTTP messages, the Content-Length header must not conflict with the length of the content as framed by the protocol. If the body is 120 bytes, the header says 120, or you leave the header off and let the library choose chunked or frame based framing.
This is the sending side of V4.2.1. If you build requests or responses, you must not be the source of a smuggling mismatch.
Why it matters
Gateways, API clients, mock servers and custom proxies often build HTTP by hand. A wrong Content-Length is easy to write, especially after a body is compressed, re encoded or templated. Downstream parsers then disagree about where the message ends, which is the exact condition smuggling attacks need.
Character count versus byte count is the classic source. A string with accented letters is longer in UTF-8 bytes than in characters, and the header ends up short.
How to implement it
Do not set Content-Length by hand if the library can do it. Let the HTTP client or server compute it from the final body bytes.
When you must set it, compute it from the encoded buffer, after all transformations:
const body = Buffer.from(JSON.stringify(payload), 'utf8');
res.writeHead(200, {
'Content-Type': 'application/json',
'Content-Length': body.length, // bytes, not string length
});
res.end(body);
For proxies, drop the original Content-Length when you change the body, and never copy both Content-Length and Transfer-Encoding forward. In HTTP/2, remove any Content-Length that does not equal the DATA total.
How to test it
Write a test that captures what your code puts on the wire, and compares header to body.
raw = capture_response(app, "/report")
head, body = raw.split(b"\r\n\r\n", 1)
declared = int(re.search(rb"Content-Length: (\d+)", head).group(1))
assert declared == len(body)
Include cases with non ASCII text, compressed bodies, empty bodies, and responses to HEAD requests. Also run a proxy in front and check that it never forwards both framing headers.
Common mistakes
- Using string length instead of byte length.
- Computing the header before gzip or template rendering changes the body.
- Copying hop by hop and framing headers when forwarding in a proxy.
- Hand building HTTP over raw sockets in tests and then reusing that code in production.
Quick check
Why is string length risky as a Content-Length value?
Multi byte characters make the encoded body longer than the character count, so the header is too small and the message framing is wrong.
Sources
- OWASP Application Security Verification Standard, requirement V4.2.2 (level 3)
- RFC 9110, Content-Length