Request Smuggling

Request Smuggling

HTTP request smuggling exploits disagreements between HTTP processors about where one request ends and the next begins. When two servers parse the same byte stream differently, an attacker can hide a request inside another.

How Smuggling Works

In a typical architecture, requests flow through layers:

Client  →  CDN / Load Balancer  →  Application Server
           (front-end)              (back-end)

Both must parse the HTTP stream to determine request boundaries. HTTP/1.1 provides two mechanisms:

  1. Content-Length — an explicit byte count of the body
  2. Transfer-Encoding: chunked — body sent in length-prefixed chunks

When a request contains both headers, or contains them in ambiguous forms, different servers may disagree on the body length. This lets an attacker smuggle a second request inside the first.

CL.TE Example

POST / HTTP/1.1
Host: example.com
Content-Length: 13
Transfer-Encoding: chunked

0\r\n\r\nSMUGGLED

Front-end (uses CL: 13): forwards all 13 bytes as one request. Back-end (uses TE: chunked): reads chunk 0 (end), leaves SMUGGLED as the next request.

Real-World Impact

  • Bypass authentication — smuggle requests past WAF/auth layers
  • Poison web caches — inject responses cached for other users
  • Hijack sessions — prepend attacker headers to other users’ requests
  • Exfiltrate data — redirect internal responses to attacker endpoints

Scored vs Unscored

Some smuggling tests are unscored because the RFC permits multiple interpretations:

  • OWS trimming (Content-Length: 42 with extra space)
  • Case-insensitive TE matching (Chunked vs chunked)
  • Trailing whitespace in values

For these, 400 is the strict/safe response and 2xx is RFC-compliant. Http11Probe shows 2xx as a warning but does not count it against the score.

Tests

Scored

CL-TE-BOTH
Both Content-Length and Transfer-Encoding present.
DUPLICATE-CL
Two Content-Length headers with different values.
CL-LEADING-ZEROS
Content-Length with leading zeros (007).
CL-NEGATIVE
Negative Content-Length value.
TE-XCHUNKED
Unknown TE ‘xchunked’ with CL present.
TE-TRAILING-SPACE
TE ‘chunked ’ with trailing space.
TE-SP-BEFORE-COLON
Space before colon in Transfer-Encoding.
CLTE-PIPELINE
Full CL.TE smuggling payload.
TECL-PIPELINE
Full TE.CL smuggling payload.
CL-COMMA-DIFFERENT
Comma-separated CL with different values.
TE-NOT-FINAL-CHUNKED
Chunked is not the final transfer encoding.
TE-HTTP10
Transfer-Encoding in HTTP/1.0 request.
CHUNK-BARE-SEMICOLON
Bare semicolon in chunk size.
BARE-CR-HEADER-VALUE
Bare CR in header value.
CL-OCTAL
Content-Length with octal prefix.
CHUNK-UNDERSCORE
Underscore in chunk size.
TE-EMPTY-VALUE
Empty Transfer-Encoding value with CL.
TE-LEADING-COMMA
Leading comma in Transfer-Encoding.
TE-DUPLICATE-HEADERS
Two TE headers with conflicting values.
CHUNK-HEX-PREFIX
Chunk size with 0x prefix.
CL-HEX-PREFIX
Content-Length with 0x prefix.
CL-INTERNAL-SPACE
Space inside Content-Length value.
CHUNK-LEADING-SP
Leading space in chunk size.
CHUNK-MISSING-TRAILING-CRLF
Chunk data without trailing CRLF.
CHUNK-EXT-LF
Bare LF in chunk extension (TERM.EXT vector).
CHUNK-SPILL
Chunk declares size 5 but sends 7 bytes.
CHUNK-LF-TERM
Bare LF as chunk data terminator.
CHUNK-EXT-CTRL
NUL byte in chunk extension.
CHUNK-LF-TRAILER
Bare LF in trailer section termination.
TE-IDENTITY
Transfer-Encoding: identity (deprecated) with CL.
CHUNK-NEGATIVE
Negative chunk size (-1).

Unscored