HTTP Connection Request Smuggling
HTTP connection request smuggling is a connection-state / routing problem rather than a classic CL.TE/TE.CL parser discrepancy. The bug appears when a front-end decides where a connection is allowed to go only once, then silently reuses that same TCP/TLS connection for later requests with a different Host or :authority.[1][2]
If you need the classic length-confusion variants, see HTTP Request Smuggling / HTTP Desync Attack and Request Smuggling in HTTP/2 Downgrades.
Connection-State Attacks
First-request Validation
When routing requests, reverse proxies often depend on the Host header (or :authority in HTTP/2) to decide the destination back-end server and whether that destination is allowed. A recurring bug class is that this whitelist is only enforced on the first request on a connection. After that, the front-end trusts the connection itself instead of re-validating each request:
GET / HTTP/1.1
Host: allowed-external-host.example
GET /admin HTTP/1.1
Host: internal-only.example
This turns connection reuse into an SSRF-like primitive against internal virtual hosts, admin panels, debug routes, and alternate tenants sharing the same edge.[1]
First-request Routing
Some reverse proxies map the entire back-end connection to a destination pool based only on the first request they forward. Every later request on that client connection is then sent to the same upstream, even if the Host header changes. This is especially useful when combined with Host header attacks such as password-reset poisoning, cache poisoning, or virtual-host brute forcing:
GET / HTTP/1.1
Host: public.example
POST /pwreset HTTP/1.1
Host: private.internal
[!TIP] PortSwigger’s HTTP Request Smuggler extension includes a connection-state probe specifically for these cases. They are easy to dismiss as “just connection reuse” or “just pipelining”, so always confirm with a fresh-connection control request.
Why this is different from classic desyncs
- No CL/TE ambiguity is required. The dangerous behavior is the routing/authorization decision being cached per connection.
- Reuse is mandatory. If the front-end or browser opens a new connection for the second request, the attack dies.
- False positives are common. Ordinary HTTP pipelining/reuse can look suspicious, so re-test the same request on a brand-new connection and compare the response origin, headers, and status code.
Browser-Powered Connection-State Abuse (2022-2025)
The most practical modern variant is browser-powered exploitation. A victim first opens a legitimate connection to an attacker-controlled or attacker-triggered origin, and the browser later reuses or coalesces that connection for a different authority.[1]
Coalescing preconditions worth checking
For HTTP/2 and HTTP/3, prioritize targets where several hostnames share the same edge infrastructure:
- The certificate presented on the existing connection is valid for both the attacker-controlled hostname and the target hostname.
- For classic HTTP/2 coalescing, browsers commonly require the hostnames to resolve to the same edge / overlapping IP set.
- ORIGIN frames can further expand which authorities are considered reusable on an existing HTTP/2 connection, so “same IP” is not the whole story anymore.
- Shared CDNs, API gateways, WAFs, service meshes, Alt-Svc / HTTP/3 endpoints, and wildcard certificates increase the odds of cross-origin reuse.
- The front-end performs routing or host validation only once instead of per request / per stream.
Exploitation scenario
- The attacker controls
evil.com, which terminates on the same shared edge asinternal.company. - The victim opens
https://evil.com/and the browser establishes an HTTP/2 or HTTP/3 connection. - The attacker causes the victim to request
https://internal.company/...(for example via an<img>,fetch(), or redirect chain). - The browser reuses the existing connection because the endpoint looks authoritative for both origins.
- If the edge only validated the first request, the later request to
internal.companyis routed or authorized using stale connection state.
[!NOTE] A hardened deployment may respond with
421 Misdirected Requestwhen a reused connection is not valid for the new authority. Seeing421is usually a good sign: the server noticed the connection was coalesced but refused to trust it.
Practical testing workflow
HTTP/1.1 manual probe
printf 'GET / HTTP/1.1\r\nHost: public.example\r\nConnection: keep-alive\r\n\r\nGET /admin HTTP/1.1\r\nHost: internal.example\r\nConnection: close\r\n\r\n' \
| openssl s_client -quiet -connect target:443
If the second response clearly belongs to internal.example, or if back-end behavior changes only when both requests share one socket, investigate further.
HTTP/2 workflow
- In Burp Repeater, enable Allow HTTP/2 ALPN override so you can test hidden HTTP/2 support even when the server does not advertise it.
- Send an initial request to an allowed host / authority.
- Reuse the same Repeater tab / same connection and change only
:authority(or the target path) for the next request or stream. - Repeat the exact same second request from a fresh connection as a control.
- A genuine issue normally shows a routing / authorization difference that exists only on the reused connection.
High-value chains
Connection-state flaws combine particularly well with:
- Internal virtual-host enumeration and access to admin panels or preview environments.
- Host header attacks such as password-reset poisoning or cache poisoning on an internal / alternate vhost.
- Client-side desync and browser-assisted queue poisoning techniques from Browser HTTP Request Smuggling.
- HTTP/2 downgrade gadgets from Request Smuggling in HTTP/2 Downgrades when you need a second primitive to poison a shared back-end connection.
Related State-Transition Abuse: h2c Upgrade Tunnelling
A closely related bug appears when a front-end forwards Upgrade: h2c and, after the 101 Switching Protocols, stops inspecting the traffic and simply tunnels bytes to the back end. In practice, the proxy may enforce routing / ACLs only on the initial HTTP/1.1 request, after which the attacker speaks raw clear-text HTTP/2 directly to the internal service.
GET / HTTP/1.1
Host: public.example
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: AAMAAABkAAQCAAAAAAIAAAAA
This is worth testing on reverse proxies that support upgrade-style tunnelling or permissive proxy_pass rules.
Tooling
- HTTP Request Smuggler (Burp) – useful for connection-state probes, hidden-HTTP/2 testing, browser-powered desync work, and modern parser-discrepancy detection.
http2smugl– purpose-built for finding HTTP/2 → HTTP/1.1 downgrade smuggling paths and related request poisoning opportunities.smugglefuzz– a Go-based downgrade smuggling scanner with customizable gadget lists and fast bulk probing.h2cSmuggler– focuses onUpgrade: h2ctunnelling mistakes that bypass front-end ACLs.
Mitigations
- Re-validate
Host/:authorityon every request and every HTTP/2 stream, not just once per socket. - Keep internal and external hostnames on separate certificates / origin sets / Alt-Svc advertisements when possible.
- Return
421 Misdirected Requestwhen a reused connection is not authoritative for the new origin. - Strip or hard-code
Upgrade: h2cat the edge unless it is explicitly required. - Where feasible, avoid reusing a single privileged upstream connection across unrelated tenants or trust zones.