Timing Oracles for HTTP Desync and Request Smuggling Detection
A request hangs for ten seconds. Is that request smuggling, a sleepy origin, or your VPN having a bad night? Timing oracles are useful because parser disagreement can force one server to wait for bytes that the other server thinks are unnecessary. They are also noisy enough to waste an afternoon if you skip controls.
Start with the parser question. In CL.TE, the front end trusts Content-Length and the back end reads chunked framing. In TE.CL, those roles swap. A carefully sized body completes for one parser but remains incomplete for the other. The backend wait becomes your observable signal.
Build a baseline before the clever payload
Send ten ordinary requests to a cheap, stable endpoint. Record median and slowest response times. Repeat through the same Burp route you will use for probes; changing proxy paths ruins the comparison. If normal responses range from 200 ms to eight seconds, a ten-second “oracle” says very little.
Use a unique query canary and disable automatic retries. A client retry can make one probe look like two parser events. Keep authentication and body size constant between control and test.
For a CL.TE candidate, the test can send a chunked body whose terminating chunk is positioned differently from the Content-Length boundary. If the back end follows TE and waits for the missing chunk terminator, the response tends to arrive at its read timeout. Reverse the framing logic for TE.CL. PortSwigger's detection guide provides safe payload shapes; use those rather than improvising malformed requests against production.
What repeatability looks like
Run control, probe, control—then pause. A credible oracle has three traits:
- The probe repeatedly lands near a stable timeout, such as 10 or 30 seconds.
- Adjacent controls return near baseline.
- A one-byte framing change removes or flips the delay.
That third check matters. It ties the timing to message boundaries instead of generic application slowness. Try both a known-valid chunked request and an intentionally incomplete comparison. If everything hangs, you found a slow endpoint.
Pause-based desync
Modern targets may reject obvious CL/TE ambiguity but still stream request bodies unsafely. Pause-based techniques send headers, wait, then continue the body. The front end may forward partial data while the back end times out and treats later bytes as a fresh request.
This testing needs a client that controls write timing precisely. Burp extensions and Turbo Intruder-style scripts can do it; a pasted Repeater request usually cannot. Keep the pause just over the suspected backend timeout and test on your own connection. One or two confirmations are enough.
From timing to reportable impact
A timeout is detection evidence, not the full impact story. Confirm the architecture with a harmless desync canary if policy permits: smuggle a request to a nonexistent path and see whether your own next request receives its response. Never leave a poisoned prefix that could consume a stranger's request.
Document exact elapsed times, protocol, request bytes, connection reuse, and controls. Mention whether the behavior survives a fresh TLS connection and whether HTTP/2 downgrade is involved. Screenshots of Burp's stopwatch are weaker than a small table of raw timings in the report.
False positives often come from WAF inspection, queue saturation, Expect: 100-continue, or an endpoint that waits for an upstream service. Test a static-looking route and compare response headers to identify edge-generated errors.
PortSwigger's finding request smuggling vulnerabilities guide documents timing techniques and the correct probe order. Keep the proof bounded. A clean oracle plus a self-contained canary beats aggressive response theft every time.