Most ways to split the boundary between two HTTP servers lean on a header trick, a fight between Content-Length and Transfer-Encoding that makes a front end and a back end count a body differently. A pause based desync attack needs none of that. The attacker sends a request that is deliberately incomplete, then stops sending, and lets the clock do the splitting. This is a timing variant of http request smuggling, and it can work against servers that parse length correctly, because the disagreement it exploits is about when a request ends in time, not how long its declared body is.
To see why that matters, remember that a front end and a back end share one long lived connection and both slice a continuous byte stream into separate requests. In a classic desync they disagree about a length header. Here they disagree about a pause. One server decides the request is finished at the moment the bytes stop arriving, and the other keeps waiting for more. The gap between those two decisions is where a second request gets smuggled in.
How a deliberate pause creates the desync
Every server that reads a request body has a read timeout and some buffering. It will wait only so long for the next byte before it gives up or acts on what it already has. An attacker who controls the timing of the bytes can push the two servers into different states by sending part of a request and then holding still.
Picture the attacker opening a connection and sending headers that promise a body, then sending the first slice of that body and pausing. If the front end flushes what it has to the back end when its own timer fires, while the back end still believes more of the body is coming, the two servers now hold different ideas about where this request stops. When the attacker finally sends the rest, one server reads it as the tail of the original request and the other reads it as a brand new request on the same connection. That leftover, attacker written chunk becomes a smuggled prefix with no header fight anywhere in sight.
The early response case, or the pause based desync attack without any length trick
The sharpest form of this is the style often written as 0.CL, where the back end emits a response before it has read the body at all. Plenty of endpoints do this. A path that always answers with a redirect, or one that rejects the request on a quick check, can return its response the instant it sees the request line and headers, without ever touching the body.
Consider a request aimed at such a path:
POST /go HTTP/1.1 Host: acme-notes.example Content-Length: 44 GET /admin HTTP/1.1 Host: acme-notes.example X: y
Suppose /go always answers with an immediate redirect and never reads the body. The back end sees the request line, decides to reply, sends the redirect, and considers this request done having consumed zero body bytes. The front end, meanwhile, trusts the Content-Length: 44 and still thinks those 44 bytes belong to the request it forwarded. Those 44 bytes are the smuggled GET /admin. They sit in the back end buffer, and the back end now treats them as the first bytes of the next request on the connection.
The pause is what makes this reliable. The attacker sends the headers, waits for the early redirect to come back, and only then sends the body bytes, so the smuggled request lands cleanly as a fresh request rather than racing the first one. The timing, not a crafted header, is doing the work of choosing a new boundary.
A pause based desync attack turns a server’s own patience against it. A gap in time, not a header that lies about length, is what decides where one request ends and the next one begins.
Why this variant is hard to catch
A length based smuggle leaves a fingerprint. A request carrying both Content-Length and Transfer-Encoding is suspicious on its face, and a careful front end can reject it. A pause based desync attack sends requests that are each well formed. There is no duplicate header to flag, no illegal value, nothing that looks wrong byte by byte. The anomaly lives in the timing of the stream and in one endpoint that answers early, which no request filter is built to notice.
That is also why testing for it means watching behavior rather than scanning content. A tester sends a request through an intercepting proxy, holds part of the body, and watches whether the connection behaves as if a second request is now queued. The signal is a response that arrives too early or a follow up request that comes back changed. Teams who want the full checklist can read our notes on detecting http request smuggling, since the detection work is the same family regardless of whether a header or a pause caused the split.
Once the split exists, the consequences are the ones every desync shares. The attacker can poison the shared connection so the next user is served the wrong answer, a problem we cover under response queue poisoning. They can capture a victim’s request into an attacker readable field. They can slip a request past a front end that only ever inspected the harmless looking outer request. The entry road is new, but the town it leads to is familiar.
Shutting the pause based route
The fixes rhyme with the rest of the desync family, with one addition aimed at timing. Front ends and back ends in one chain should agree on read timeout behavior, so one of them does not flush a half read request while the other waits. An endpoint that can answer before reading the body should still drain or discard that body, or the server should close the connection after an early response so no leftover bytes can wait for a victim. End to end HTTP/2 helps here too, because its framing marks message boundaries explicitly and leaves no room for a pause to be read two ways. More broadly, this is an input handling flaw, the kind we group under injection and input, where the bug is in how a boundary is parsed rather than in any single value.
What makes this class worth real attention is that it hides inside normal looking traffic, so finding it means reasoning about what each server assumes about timing rather than matching a payload. When UnboundCompute probes for a desync like this, it confirms the smuggled request actually reaches an impactful sink before reporting, so a timing quirk is only called a finding once it is shown to move a real request somewhere it should never go. You can read more about that approach on our about page. The attack is quiet by design, and the defense is to stop assuming two servers will ever agree on when silence means a request is done.
Frequently asked questions
What is a pause based desync attack?
It is a timing variant of request smuggling where the attacker sends an incomplete request and then pauses. A server read timeout or an early response makes one server decide the request is finished while the other waits for more, so the leftover bytes become a smuggled request on the shared connection.
How is it different from a CL.TE or TE.CL smuggle?
Those variants rely on a length header disagreement, so a request carries both Content-Length and Transfer-Encoding and the two servers count the body differently. A pause based desync needs no conflicting header. The split comes from the timing of the bytes and from an endpoint that answers before reading the body.
What is the 0.CL style?
It is the case where a back end sends a response before reading any body, so it treats the request as having zero body bytes while the front end still trusts the declared Content-Length. The declared body bytes, written by the attacker, then sit in the buffer and are parsed as the start of the next request.
How do you defend against it?
Align read timeout behavior across the front end and back end, drain or discard the body on endpoints that answer early, and close the connection after an early response so no leftover bytes can wait for a victim. End to end HTTP/2 also removes the ambiguity because its framing marks message boundaries explicitly.
Put an autonomous researcher on your own systems
UnboundCompute is an autonomous security researcher that reasons about how an application fits together and proves the access control and injection bugs it finds. We are opening a small number of founding design partner seats: private early access pointed at a staging target you choose, and a say in what it looks for. If your team ships software worth pressure testing, apply to the design partner program.
