pwneglyph logo
web python request-smuggling http-desync gunicorn hypercorn transfer-encoding

Desync a frontend and a Python backend that disagree on TE/CL, whitespace, or line endings to inject a second request.

Request Smuggling against Hypercorn / Gunicorn

Different HTTP hops disagree about where one request ends and the next begins. If the frontend and the Python backend parse Transfer-Encoding, Content-Length, whitespace, or line endings differently, attacker-controlled bytes escape into the backend as a second request.

Why It Works

  • The bug is architectural: a reverse proxy / WAF / frontend making one parsing choice and the backend making another is enough.
  • Known weaknesses include Gunicorn TE handling, Hypercorn line-ending leniency, and latin1 header-name confusion.

Vulnerable Pattern

  • Apache, Traefik, Nginx, or a custom frontend talking to Gunicorn/Hypercorn over keep-alive HTTP/1.1.
  • Any chain where the proxy and backend differ on hop-by-hop header parsing.

Exploit Flow

  1. Identify the exact hop chain — smuggling only matters if the backend sees bytes the proxy didn't model as a second request.
  2. Test TE.CL and CL.TE with raw requests before exotic variants.
  3. If classic probes fail, mutate Transfer-Encoding syntax: commas, tabs, duplicate headers, NBSP, odd line endings.
  4. Once desync is confirmed, target internal-only routes, alternate vhosts, cache poisoning, or request-body confusion on admin endpoints.

Variations

  • Transfer-Encoding: chunked,gzip, TE:\tchunked, header-name NBSP, mixed \n vs \r\n, or HTTP/0.9 / response-splitting style backend confusion.
  • If the backend route isn't directly useful, aim for an internal upload, debug route, or secondary proxy endpoint.

Common Blockers

  • Connection reuse disabled between hops, frontend normalization that fixes the backend bug, or no useful internal target even after desync.
  • A backend 404 isn't enough — confirm the smuggled request actually reached the route you care about.

PoC Sketch

Transfer-Encoding: chunked
Content-Length: 4

0\r\n\r\nGET /internal/upload HTTP/1.1\r\nHost: backend\r\n\r\n
# then mutate TE to values like chunked,gzip or TE:\tchunked

Good Situations To Use It

  • A multi-hop HTTP/1.1 chain with keep-alive between proxy and a Python app server.
  • You have a known internal-only route worth reaching.
  • Classic TE/CL probes already show parsing differences.

Sources

  • 0xFUN2026/web/skyport_ops
  • fcsc2026/web/bubulle_corp_2
  • sthack2026/web/magic_claw_2
  • ehaxctf2026/web/megacorp (lead)
  • ehaxctf2026/web/modernshop (lead)