Slowloris: an outage with almost no traffic
Slowloris takes a site down by opening many connections and never finishing the requests on them. Each connection sends part of a request, then keeps trickling just enough to avoid being closed as idle. The server holds every one of them open, waiting for a request that never completes, until it has nothing left to hold.
Quick facts
- Layer
- Application (7), consuming connection slots
- Vector
- Many connections carrying deliberately unfinished requests
- Goal
- Occupy every slot the server can serve from
- In your logs
- Many open connections, very few bytes, almost no completed requests
- Does a WAF stop it?
- Yes, though by architecture rather than by rules: a layer that buffers the whole request absorbs it
That qualifier matters. Nothing about the traffic is recognisably hostile; what defeats it is where the incomplete request is held.
The mechanism
A request is not a single event. It arrives as a series of lines, and the server knows it is complete only when it sees the marker that ends the headers. Until then, the connection is legitimately in progress, and closing it would break clients on slow networks.
An attack exploits that patience. It sends the opening line, then one header at a time, spaced out enough to stay under any idle timeout and slow enough that the request never finishes. Multiply that across as many connections as the server will accept, and every slot is occupied by something that will never become a request.
Two properties make this unusual.
Bandwidth is negligible. The whole attack can run from a single ordinary connection, because volume is not the resource being consumed. A network graph shows nothing.
Nothing sent is invalid. Every byte is a well-formed part of a legitimate request. There is no malformed input, no signature, and no threshold of requests per second to trip, because requests are never completed and therefore never counted.
Why some servers barely notice
The difference is architectural, and it explains why the same attack ends one site and leaves another unaffected.
Servers that dedicate a worker to each connection have a hard ceiling: when workers are occupied, new visitors wait regardless of how idle the machine is. Servers built around an event loop hold connections as cheap entries instead, so the ceiling is far higher and an attack needs proportionally more connections to reach it.
Neither design is immune. The second raises the cost enough that the technique usually stops being practical, which is a different statement from immunity, and the difference matters when someone says their stack is not vulnerable.
What you see
# Illustrative connection picture; values are shape, not measurements.
Open connections high: far above the usual concurrency
Bytes transferred very low relative to the connection count
Connection age long: many sitting in the same state for minutes
Completed requests near zero; access log barely grows
Processor / memory normal: nothing is being processed
The distinguishing combination is high connection count with near-zero throughput. A genuine traffic surge raises both. This raises one and leaves the other flat, which is the single most reliable indicator.
Where the server logs timed-out requests, those entries appear in numbers that do not match any plausible client behaviour. Their absence proves nothing, since not every configuration records them.
Before you tighten timeouts
Warning: the standard fix is to shorten how long a server waits for a request to arrive, and set too aggressively it disconnects real people.
The clients that suffer first are the ones already having a difficult time: mobile connections in poor coverage, distant regions with high latency, and anyone uploading a large file over a slow link. Those requests are also slow to arrive, and a timeout cannot tell the difference between a slow client and a deliberate one, because there is no difference in what is sent.
So the useful form of the measure is narrower than "reduce the timeout". Limit the time allowed for headers, which no legitimate client needs to spend minutes on, and treat the body separately, since uploads legitimately take time. Where a server supports requiring a minimum data rate rather than an absolute deadline, that expresses the intent better: it closes connections that are not making progress instead of connections that are merely slow.
Mitigation by layer
Four measures, most effective first.
Put a buffering layer in front. Where a proxy accepts the whole request before passing it on, the incomplete ones are held there and your application never sees them. This is the defence that removes the problem rather than tuning around it, and it is why sites behind a terminating edge are largely unaffected.
Limit concurrent connections per source. An attack from few addresses runs into this immediately. It helps less against many sources, and it misfires where many users share an address, which is the usual trade-off.
Bound header time and require progress. As described above, applied to headers rather than to whole requests.
Prefer an event-driven front end. Raising the ceiling does not solve the mechanism, and it converts an outage into a non-event at the volumes this technique can reach.
What does not help: request rate limits, since requests are never completed, and rules matching request content, since the content is ordinary.
Telling it apart
Two lookalikes to rule out before acting.
A slow upstream or database produces long-lived connections too, but with processing behind them: workers are busy, not waiting, and processor usage reflects it.
Legitimate slow clients appear in small numbers, spread across different paths, and complete eventually. The attack shows many connections in the same state, opened close together, that never complete at all.
Why it survived being famous
The technique has been documented for many years, which raises the question of why it still works anywhere.
Part of the answer is that the vulnerable design is not a defect. Serving each connection from its own worker is a reasonable architecture with real advantages, and the ceiling it imposes only becomes a problem when someone deliberately holds slots empty.
The rest is that the defence lives in a component many deployments do not have. A site served directly by an application server, without anything buffering in front, is exposed by its shape rather than by its configuration, and that shape is common in internal tools, staging environments, and anything assembled quickly.
Those are also the systems least likely to be watched, which is why the symptom is usually reported by a person who could not load a page rather than by monitoring.
Where the platform sits
This is a case where the platform's structure matters more than any rule. Requests reach your origin through the platform's edge, which accepts a complete request before forwarding it, so connections held open with unfinished requests are absorbed there rather than occupying your server. Rate limiting is applied per domain, which bounds the volume accepted for the domain as a whole. What this does not address is traffic that saturates a link, which belongs to a different layer. See what the platform offers at Bridge CDN.
Questions
What is a Slowloris attack?
An attack that opens many connections and sends each request so slowly that none of them ever finishes, occupying every slot the server has available. The server is not overloaded in any conventional sense; it is simply fully booked by clients that never leave.
Why does it use so little bandwidth?
Because the resource being consumed is connection slots rather than capacity, and holding a slot open costs the sender almost nothing to sustain. That asymmetry is the whole point of the technique: the defender's limit is reached long before the sender's is approached.
Does a WAF stop Slowloris?
When it buffers the complete request before passing anything backwards, yes, because the slow connection then terminates at something built to hold very many of them at once. Content-matching rules contribute nothing here, since everything sent is valid and merely unfinished.
Are all servers vulnerable?
Not equally. Architectures that dedicate a worker to each connection reach their limit first, because that limit is small and every held connection consumes one of them. Event-driven designs raise the cost considerably without being immune, since connection slots remain finite in any design.
Will shorter timeouts fix it?
Partly, and a flat deadline set aggressively enough to help will disconnect mobile users and interrupt large uploads. The better shape is to require forward progress and to constrain the time allowed for headers separately from the time allowed for a body.
How do I recognise it?
By a combination that occurs in no other situation: a high count of open connections, almost no bytes transferred across them, almost no completed requests, and a machine whose processor and memory readings look entirely untroubled while the service is unreachable.
Structure rather than rules: the edge accepts a complete request before forwarding it, so unfinished ones are held there.
off
No request is inspected. Where the incomplete request is held is a separate property.
monitor
Matches are recorded on requests that completed — which these, by design, never do.
block
Refusal happens on complete requests, after the edge has assembled one.
The firewall layer is included with Bridge CDN. Start in monitor: nothing is refused until you decide it should be.
Get started