daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

http-connection-request-smuggling.md (9129B)


      1 ---
      2 title: "HTTP Connection Request Smuggling"
      3 section: "Web Pentesting"
      4 sectionSlug: "pentesting-web"
      5 sourcePath: "src/pentesting-web/http-connection-request-smuggling.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/http-connection-request-smuggling.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # HTTP Connection Request Smuggling
     14 
     15 **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`.<sup>[[1]](#references)[[2]](#references)</sup>
     16 
     17 If you need the classic length-confusion variants, see [HTTP Request Smuggling / HTTP Desync Attack](/hacktricks/pentesting-web/http-request-smuggling/overview) and [Request Smuggling in HTTP/2 Downgrades](/hacktricks/pentesting-web/http-request-smuggling/request-smuggling-in-http-2-downgrades).
     18 
     19 ## Connection-State Attacks <a href="#state" id="state"></a>
     20 
     21 ### First-request Validation
     22 
     23 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:
     24 
     25 ```http
     26 GET / HTTP/1.1
     27 Host: allowed-external-host.example
     28 
     29 GET /admin HTTP/1.1
     30 Host: internal-only.example
     31 ```
     32 
     33 This turns connection reuse into an SSRF-like primitive against **internal virtual hosts**, admin panels, debug routes, and alternate tenants sharing the same edge.<sup>[[1]](#references)</sup>
     34 
     35 ### First-request Routing
     36 
     37 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](https://portswigger.net/web-security/host-header) such as password-reset poisoning, cache poisoning, or virtual-host brute forcing:
     38 
     39 ```http
     40 GET / HTTP/1.1
     41 Host: public.example
     42 
     43 POST /pwreset HTTP/1.1
     44 Host: private.internal
     45 ```
     46 
     47 > [!TIP]
     48 > 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.
     49 
     50 ### Why this is different from classic desyncs
     51 
     52 - **No CL/TE ambiguity is required.** The dangerous behavior is the **routing/authorization decision being cached per connection**.
     53 - **Reuse is mandatory.** If the front-end or browser opens a new connection for the second request, the attack dies.
     54 - **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.
     55 
     56 ---
     57 
     58 ## Browser-Powered Connection-State Abuse (2022-2025)
     59 
     60 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.<sup>[[1]](#references)</sup>
     61 
     62 ### Coalescing preconditions worth checking
     63 
     64 For HTTP/2 and HTTP/3, prioritize targets where several hostnames share the same edge infrastructure:
     65 
     66 - The certificate presented on the existing connection is valid for **both** the attacker-controlled hostname and the target hostname.
     67 - For classic HTTP/2 coalescing, browsers commonly require the hostnames to resolve to the **same edge / overlapping IP set**.
     68 - **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.
     69 - Shared **CDNs, API gateways, WAFs, service meshes, Alt-Svc / HTTP/3 endpoints**, and wildcard certificates increase the odds of cross-origin reuse.
     70 - The front-end performs **routing or host validation only once** instead of per request / per stream.
     71 
     72 ### Exploitation scenario
     73 
     74 1. The attacker controls `evil.com`, which terminates on the same shared edge as `internal.company`.
     75 2. The victim opens `https://evil.com/` and the browser establishes an HTTP/2 or HTTP/3 connection.
     76 3. The attacker causes the victim to request `https://internal.company/...` (for example via an `<img>`, `fetch()`, or redirect chain).
     77 4. The browser reuses the **existing** connection because the endpoint looks authoritative for both origins.
     78 5. If the edge only validated the **first** request, the later request to `internal.company` is routed or authorized using stale connection state.
     79 
     80 > [!NOTE]
     81 > A hardened deployment may respond with **`421 Misdirected Request`** when a reused connection is not valid for the new authority. Seeing `421` is usually a good sign: the server noticed the connection was coalesced but refused to trust it.
     82 
     83 ### Practical testing workflow
     84 
     85 #### HTTP/1.1 manual probe
     86 
     87 ```bash
     88 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' \
     89 | openssl s_client -quiet -connect target:443
     90 ```
     91 
     92 If the second response clearly belongs to `internal.example`, or if back-end behavior changes only when both requests share one socket, investigate further.
     93 
     94 #### HTTP/2 workflow
     95 
     96 1. 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.
     97 2. Send an initial request to an allowed host / authority.
     98 3. Reuse the **same Repeater tab / same connection** and change only `:authority` (or the target path) for the next request or stream.
     99 4. Repeat the exact same second request from a **fresh connection** as a control.
    100 5. A genuine issue normally shows a routing / authorization difference that exists **only** on the reused connection.
    101 
    102 ### High-value chains
    103 
    104 Connection-state flaws combine particularly well with:
    105 
    106 - **Internal virtual-host enumeration** and access to admin panels or preview environments.
    107 - **Host header attacks** such as password-reset poisoning or cache poisoning on an internal / alternate vhost.
    108 - **Client-side desync** and browser-assisted queue poisoning techniques from [Browser HTTP Request Smuggling](/hacktricks/pentesting-web/http-request-smuggling/browser-http-request-smuggling).
    109 - **HTTP/2 downgrade gadgets** from [Request Smuggling in HTTP/2 Downgrades](/hacktricks/pentesting-web/http-request-smuggling/request-smuggling-in-http-2-downgrades) when you need a second primitive to poison a shared back-end connection.
    110 
    111 ---
    112 
    113 ## Related State-Transition Abuse: `h2c` Upgrade Tunnelling
    114 
    115 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.
    116 
    117 ```http
    118 GET / HTTP/1.1
    119 Host: public.example
    120 Connection: Upgrade, HTTP2-Settings
    121 Upgrade: h2c
    122 HTTP2-Settings: AAMAAABkAAQCAAAAAAIAAAAA
    123 ```
    124 
    125 This is worth testing on reverse proxies that support upgrade-style tunnelling or permissive `proxy_pass` rules.
    126 
    127 ---
    128 
    129 ## Tooling
    130 
    131 - **HTTP Request Smuggler** (Burp) – useful for **connection-state probes**, hidden-HTTP/2 testing, browser-powered desync work, and modern parser-discrepancy detection.
    132 - **`http2smugl`** – purpose-built for finding **HTTP/2 → HTTP/1.1 downgrade** smuggling paths and related request poisoning opportunities.
    133 - **`smugglefuzz`** – a **Go-based** downgrade smuggling scanner with customizable gadget lists and fast bulk probing.
    134 - **`h2cSmuggler`** – focuses on `Upgrade: h2c` tunnelling mistakes that bypass front-end ACLs.
    135 
    136 ---
    137 
    138 ## Mitigations
    139 
    140 - Re-validate **`Host` / `:authority` on every request and every HTTP/2 stream**, not just once per socket.
    141 - Keep **internal and external hostnames** on separate certificates / origin sets / Alt-Svc advertisements when possible.
    142 - Return **`421 Misdirected Request`** when a reused connection is not authoritative for the new origin.
    143 - Strip or hard-code **`Upgrade: h2c`** at the edge unless it is explicitly required.
    144 - Where feasible, avoid reusing a single privileged upstream connection across unrelated tenants or trust zones.
    145 
    146 ---
    147 
    148 ## References
    149 
    150 - [1] [PortSwigger Research - Browser-Powered Desync Attacks](https://portswigger.net/research/browser-powered-desync-attacks)
    151 - [2] [PortSwigger Research - HTTP/1.1 must die: the desync endgame](https://portswigger.net/research/http1-must-die)