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.
CLTE-SMUGGLED-GET
CL.TE payload with embedded GET; multiple responses indicate request boundary confusion.
CLTE-SMUGGLED-HEAD
CL.TE payload with embedded HEAD; multiple responses indicate request boundary confusion.
TECL-SMUGGLED-GET
TE.CL payload (chunk-size prefix trick); multiple responses indicate request boundary confusion.
TE-DUPLICATE-HEADERS-SMUGGLED-GET
Duplicate TE headers + CL with embedded GET; multiple responses indicate request boundary confusion.
DUPLICATE-CL-SMUGGLED-GET
Duplicate Content-Length + embedded GET; multiple responses indicate request boundary confusion.
CLTE-SMUGGLED-GET-TE-TRAILING-SPACE
CL.TE smuggled GET with TE trailing space.
CLTE-SMUGGLED-GET-TE-LEADING-COMMA
CL.TE smuggled GET with TE leading comma.
CLTE-SMUGGLED-GET-TE-CASE-MISMATCH
CL.TE smuggled GET with TE case mismatch.
CLTE-SMUGGLED-GET-CL-PLUS
CL.TE smuggled GET with malformed Content-Length (+N).
CLTE-SMUGGLED-GET-CL-NON-NUMERIC
CL.TE smuggled GET with non-numeric Content-Length (N).
CLTE-SMUGGLED-GET-TE-OBS-FOLD
CL.TE smuggled GET with obs-folded Transfer-Encoding.
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.
CHUNK-EXT-INVALID-TOKEN
Invalid token character in chunk extension name.
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.
CHUNK-SIZE-PLUS
Chunk size with leading plus sign.
CHUNK-SIZE-TRAILING-OWS
Chunk size with trailing whitespace.
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-INVALID-SIZE-DESYNC
Invalid chunk size plus poison-byte follow-up check.
CHUNK-LF-TERM
Bare LF as chunk data terminator.
CHUNK-EXT-CTRL
NUL byte in chunk extension.
CHUNK-EXT-CR
Bare CR inside chunk extension metadata.
CHUNK-LF-TRAILER
Bare LF in trailer section termination.
TE-IDENTITY
Transfer-Encoding: identity (deprecated) with CL.
TE-VTAB
Vertical tab before chunked token.
TE-FORMFEED
Form-feed before chunked token.
TE-NULL
NUL byte appended to chunked token.
CHUNK-NEGATIVE
Negative chunk size (-1).
CHUNK-BARE-CR-TERM
Bare CR as chunk size line terminator.
CL-UNDERSCORE
Content-Length with underscore digit separator (1_0).
CL-NEGATIVE-ZERO
Content-Length: -0 — not valid 1*DIGIT.
CL-DOUBLE-ZERO
Content-Length: 00 — leading zero ambiguity.
CL-LEADING-ZEROS-OCTAL
Content-Length: 0200 — octal vs decimal disagreement.
TE-OBS-FOLD
Transfer-Encoding with obs-fold line wrapping.
OPTIONS-TE-OBS-FOLD
OPTIONS path for TE obs-fold plus follow-up close check.
TE-TRAILING-COMMA
Transfer-Encoding: chunked, — trailing comma.
MULTIPLE-HOST-COMMA
Host with comma-separated values.

Unscored