A Slowloris attack is an application layer denial of service that opens many HTTP connections to a web server and leaves every one of them unfinished, so the worker handling each connection never gets to finish its job. It costs almost no bandwidth, and one laptop is enough. Robert Hansen released the original Perl tool in 2009, and the weakness it demonstrated is still catalogued as CVE-2007-6750. This guide walks through the request sequence, the servers it reaches, the symptoms that give it away, and the settings that close the door. Start with the odd part: your bandwidth graph barely moves.
Key Takeaways
- A Slowloris attack sends partial HTTP requests and never sends the blank line that ends a header block, so the server keeps each connection open and waiting.
- The target is the connection pool, not the network link, which is why a slow HTTP attack can run over a residential connection.
- Thread per connection servers such as Apache running the prefork or worker MPM are the most exposed, since each held socket consumes a worker.
- Apache ships mod_reqtimeout from version 2.2.15 onward, and its RequestReadTimeout directive is the single most effective server side fix.
- Event driven servers including nginx, IIS, Node.js and Go handle the attack far better, though file descriptor limits still set a ceiling.
- The signature is a climbing count of open connections while inbound bandwidth stays flat, a pattern that volume based alerting misses entirely.
- Complete protection combines short header timeouts, per source connection caps, and an edge layer that terminates requests before they reach the origin.
What Is a Slowloris Attack and Why Does It Work?
A Slowloris attack is a low and slow denial of service technique that exhausts a web server’s concurrent connection capacity by holding hundreds of HTTP requests in a permanently incomplete state. The server believes each client is simply slow, so it waits, and while it waits the worker assigned to that connection is unavailable to anyone else.
The mechanics rest on a rule in HTTP itself. A request header block ends with an empty line. Until the server sees that empty line, it has no way to know whether the client has finished, so it holds the socket and keeps reading. That patience is the attack surface.
Think of a ticket counter where every person in line starts a sentence, pauses, and adds one more word every fifteen seconds. Nobody is shouting. Nobody is breaking a rule. The queue still stops moving.
The technique is also supported by established security testing tools and frameworks. For example, the Metasploit Framework includes a Slowloris module, which is one reason this technique frequently appears in penetration testing and defensive security assessments rather than only in academic discussions.
Because the attack drains a resource that bandwidth graphs never show, it belongs in the same planning conversation as DDoS attack protection, not in a separate box labelled edge case. The controls overlap, but the trigger conditions do not.
So if the request never finishes, what exactly is the server doing for those minutes? The step by step sequence answers that.
How Does a Slowloris Attack Work
A Slowloris attack works by opening a large number of TCP connections, sending an incomplete HTTP header block on each, and then trickling a single additional header at an interval short enough to stay inside the server’s idle timeout. The request is never completed and never abandoned.

The attack sequence, and the missing blank line that keeps every request technically unfinished.
- Open the sockets. The tool establishes hundreds of TCP connections to port 80 or port 443. Nothing here looks abnormal, because opening a connection is what every browser does.
- Send a partial header block. Each connection receives a request line such as GET /index.html HTTP/1.1 followed by a Host header and a User-Agent header.
- Withhold the terminating blank line. The empty CRLF that signals the end of the headers is never transmitted, so the request stays open by definition.
- Drip feed one header at a time. A junk header, often a repeated custom field with a random value, arrives every few seconds and resets the server’s read timer.
- Exhaust the pool. Once every worker sits in a read state, new visitors either queue behind an unavailable worker or receive a connection error.
Timing carries the attack, not volume. Send headers too fast and you are just generating traffic. Send them too slowly and the server reclaims the socket. The original tool aimed at the narrow gap between those two failures, and every variant since has tuned the same dial.
You might be thinking that TLS changes the picture. It does not. The handshake completes normally, then the same partial request runs inside the encrypted channel, which has the side effect of hiding the payload from any inspection device that is not terminating TLS.
That single behaviour, returning 408 rather than waiting, is the whole defence in one line. Whether your server does it by default depends entirely on which server you run.
Which Web Servers Are Vulnerable to Slowloris?
Vulnerability to Slowloris follows the concurrency model rather than the vendor. Servers that dedicate a process or a thread to each connection fail quickly, while event driven servers that multiplex thousands of connections through a single worker absorb the same attack with little visible effect.

Exposure tracks the concurrency model. Apache MPM defaults come from the MaxRequestWorkers directive.
| Server and mode | Concurrency model | Default ceiling | Exposure |
|---|---|---|---|
| Apache 2.4, prefork | One process per connection | 256 | High |
| Apache 2.4, worker | One thread per connection | 400 | High |
| Apache 2.4, event | Async keep-alive | 400 threads | Medium |
| nginx | Event loop | 512 per worker | Low |
| Microsoft IIS | Async I/O | Kernel queue | Low |
| Node.js and Go | Event loop / lightweight routines | No thread per socket | Low |
The Apache numbers are not estimates. The prefork MPM documentation states that sites needing more than 256 simultaneous requests must raise MaxRequestWorkers, and the worker and event MPMs derive their default from a ServerLimit of 16 multiplied by 25 threads per child. Those are the exact figures an attacker is trying to reach.
Now the part the vendor tables get wrong. Running nginx is not immunity, it is headroom. An event driven worker still consumes a file descriptor per connection, and once the process hits its descriptor limit or the worker_connections value, the outcome for a visitor is identical. Teams read the word resistant in a vendor table and stop configuring timeouts, which is how a low exposure server ends up offline anyway.
Original Slowloris documentation from 2009 also listed dhttpd and several appliance web interfaces among affected targets, a reminder that management consoles on network hardware often run the oldest and least maintained HTTP stack in the building.
Knowing your exposure is one thing. Telling the difference between this attack and an ordinary traffic surge is where most incident calls go sideways.
Slowloris vs DDoS: What Actually Separates Them
A Slowloris attack drains connection capacity from a single source using kilobits per second, while a distributed flood drains network capacity from thousands of sources using gigabits per second. Both end with an unreachable site, and almost nothing in between is the same.
Relative bandwidth footprint, source count, and the resource each attack class actually exhausts.
| Characteristic | Slowloris | Volumetric flood |
|---|---|---|
| Traffic volume | Kilobits per second | Gigabits to terabits per second |
| Sources required | One machine is sufficient | A botnet or a set of reflectors |
| Resource exhausted | Worker threads and connection pool | Link capacity and edge hardware |
| OSI layer | Layer 7, HTTP request handling | Layers 3 and 4 |
| Packet validity | Valid, well formed, incomplete | Often spoofed or malformed |
| What alerting sees | Connection count climbing alone | Bandwidth spike across the graph |
The distinction is not academic. If you have already read our breakdown of the DoS vs DDoS attack, the mental model carries directly: source count is one axis and exhausted resource is another, and Slowloris sits in the corner that most monitoring never watches.
Compare it with a volumetric DDoS attack, where a 2 Tbps peak is the story and the mitigation question is scrubbing capacity. Compare it instead with a SYN flood attack, and the family resemblance appears. Both leave connections in a half finished state, one at the TCP handshake and one at the HTTP header stage, which is why layered filtering has to cover both.
Yes, Slowloris is technically a denial of service rather than a distributed one. But nothing prevents an attacker from running the same script from 500 hosts, and at that point per source connection caps stop helping on their own. Treating the technique as harmless because it starts on one machine is the mistake that turns a five minute fix into an outage.
So what does the attack look like from inside your own dashboards while it runs?
What Are the Symptoms of a Slowloris Attack?
The defining symptom of a Slowloris attack is a large and growing number of open connections that transfer almost no data, while inbound bandwidth, request rate and CPU usage all stay close to their normal range. The site becomes unreachable without any of the usual overload indicators moving.

The two curve signature: connection count rises steadily while the bandwidth line refuses to follow.
- Connections pile up in a read state. On Linux, counting established sockets on port 443 with ss or netstat returns a number far above your usual concurrency, and it keeps rising.
- Bytes per connection collapse. Legitimate sessions move kilobytes. Attack sockets move a few dozen bytes across several minutes.
- HTTP 408 responses appear in volume once timeouts are configured, which is the good version of this symptom.
- The Apache error log records that the server reached MaxRequestWorkers, the clearest single line of evidence available.
- Every socket shares one client signature, usually an identical User-Agent string and an identical TLS client hello.
- Static assets served from cache still load while anything hitting the origin hangs, which confuses early triage badly.
That warning from CISA guidance on denial of service attacks is worth taking literally here. Slowloris produces no malformed packets and no traffic spike, so a first responder reasonably reaches for database load or a bad deploy before considering an attack.
The shared client signature is the fastest disambiguation available, and it is exactly what a ja3 fingerprint is built to expose. Hundreds of concurrent sockets presenting one identical TLS fingerprint is not a browser population, it is one script.
Symptoms tell you an attack is under way. Getting an alert to fire before the first customer email takes a different set of metrics.
How to Detect Slowloris Attacks Before Users Complain
Detecting a Slowloris attack requires monitoring connection state and per connection throughput rather than traffic volume. Alert on concurrent connections relative to your baseline, on average bytes per connection falling, and on the ratio of open sockets to completed requests.
- Baseline concurrent connections per origin over a normal week, then alert when the count exceeds roughly twice that figure for more than two minutes.
- Track average request duration for incomplete requests separately from completed ones. A rising population of requests with no response code is the earliest clean signal.
- Watch the ratio of open connections to requests per second. Under normal load these move together. During a slow HTTP attack the first climbs while the second flatlines.
- Enable Apache mod_status or the nginx stub_status module and record how many workers sit in the reading state over time.
- Alert on 408 response volume once read timeouts are enforced, because 408 is your defence reporting its own work.
- Group active connections by client fingerprint and source subnet, so a single script fanning out across 40 addresses still resolves to one actor.
A worked example makes the ratio concrete. If a site normally serves 120 requests per second across 300 open connections, that is 2.5 connections per request. During a slow header attack the request rate stays near 120 while connections climb through 800 and beyond, pushing the ratio past 6. No individual metric looks alarming, but the relationship between them breaks immediately.
Detection buys you minutes. Closing the hole is a configuration job, and it starts on the server itself.
How to Prevent Slowloris Attacks at the Server Level
Preventing Slowloris at the server level means enforcing a deadline for completing a request header block and a minimum data rate for clients that are still sending. Apache does this through mod_reqtimeout, and nginx does it through client_header_timeout and client_body_timeout.
Documented defaults from the Apache and nginx projects, with the directives that end an unfinished request.
The Apache module mod_reqtimeout has shipped since version 2.2.15, and its RequestReadTimeout directive carries a documented default of header=20-40,MinRate=500 and body=20,MinRate=500. Read plainly, that grants 20 seconds for the header block, extends the allowance by one second for every 500 bytes actually received, and refuses to wait beyond 40 seconds. A drip feeding client fails both tests.
- Confirm mod_reqtimeout is loaded. Presence in the distribution does not guarantee it is enabled, and it defaulted to disabled in Apache 2.3.14 and earlier.
- Lower Timeout from the default 60 seconds and set KeepAliveTimeout to 5 seconds so idle sockets are recycled quickly.
- Move from the prefork MPM to the event MPM wherever your PHP setup allows it, since event handles idle keep alive connections without pinning a worker to each one.
- On nginx, set client_header_timeout and client_body_timeout to 10 seconds and add limit_conn with a per address zone to cap concurrent sockets from one source.
- Add mod_qos or ModSecurity on Apache when you need per client connection accounting beyond what the core modules provide.
- Raise file descriptor limits deliberately rather than accidentally, because an event driven server that runs out of descriptors fails the same way a thread bound one does.
You might be thinking that simply increasing MaxRequestWorkers solves this. It does not. Raising the ceiling from 256 to 2000 multiplies memory consumption and moves the failure point without removing it, and an attacker adds connections faster than you add RAM. Capacity is a delay tactic, timeouts are a fix.
Server hardening also depends on nothing bypassing it. A properly tuned firewall solution ensures traffic cannot reach an application port directly while the reverse proxy in front of it holds the timeout policy.
Timeouts handle a single machine running a public script. A distributed version, or an attacker who tunes the interval carefully, needs a filter that sits further out.
Slowloris Attack Mitigation at the Network Edge
Edge based Slowloris mitigation works because a reverse proxy terminates the client connection itself, then forwards only complete requests to the origin. The held sockets pile up on distributed edge capacity that is built for millions of concurrent connections, and the application server never sees them.
Each filter removes a different property of the attack, from packet state through client identity to request policy.
This is the structural advantage of a reverse proxy WAF. Connection pooling between the proxy and the backend means 10,000 client sockets can map to a small number of upstream connections, which breaks the arithmetic the attack depends on.
- Terminate and re-form requests at the edge so an incomplete header block never occupies an application worker.
- Apply a header completion deadline in edge policy, giving you one place to enforce it across every backend rather than server by server.
- Cap concurrent connections per source address, since 200 simultaneous sockets from one client is not browser behaviour under any condition.
- Fingerprint the TLS client hello and challenge or drop the population presenting one identical hash across hundreds of sockets.
- Keep the application unreachable except through the edge, so the protection cannot be walked around by connecting to the IP directly.
Layer 7 policy is where most of the work happens. An Advanced Web Application Firewall inspects request structure rather than payload size, which is the correct lens for an attack whose payload is deliberately tiny. Pair that with rate limiting to bound how many connections and requests any single client may hold, and the economics of the attack collapse.
Below the application layer, L4 Shield handles the TCP state exhaustion half of the problem before a request is ever parsed. For known bad sources, custom IP lists turn repeat offenders into a drop decision that costs no processing at all.
None of this helps if the attacker can reach your origin server directly. Restricting inbound traffic to edge address ranges is the step teams skip most often, and it quietly undoes every other control on this list.
Slowloris is also the oldest member of a family that has kept growing, and several relatives target protocols that did not exist in 2009.
Slow HTTP Attack Variants Beyond Slowloris
Slowloris starves the server on request headers, but the same principle applies to request bodies, response reading, and HTTP/2 stream management. Defending only against the header variant leaves three documented attack paths open.
| Variant | What it holds open | Primary control |
|---|---|---|
| Slowloris | Incomplete request headers | Header read timeout and minimum rate |
| Slow POST, also called RUDY | A large declared body sent one byte at a time | Body read timeout and request size limits |
| Slow Read | A tiny TCP receive window on the response | Response write timeout and window checks |
| HTTP/2 stream abuse | Concurrent streams and queued frames | Stream concurrency caps and patched libraries |
The HTTP/2 entry is the one most teams have not audited. In 2019 Netflix disclosed eight denial of service issues affecting HTTP/2 implementations, tracked as CVE-2019-9511 through CVE-2019-9518 and covering data dribble, ping floods, resource loops, reset floods, settings floods and empty frame floods. Details are published in the Netflix security bulletin for the HTTP/2 vulnerabilities. Several are slow attacks reimagined for a multiplexed protocol, and they hit servers that were correctly hardened against the HTTP/1.1 original. None of these exhaustion techniques touch application logic the way an insecure deserialization exploit does, where a single crafted object triggers remote code execution rather than a slow drain on resources.
A RUDY attack, the slow POST variant, deserves its own check because the fix is a different directive. Apache’s body=20,MinRate=500 setting governs it, and a configuration that sets a header timeout while leaving the body unbounded is a half finished job.
Volume changes the calculus too. Distribute any of these variants across a botnet DDoS attack and per source caps lose their edge, which is when reputation data and behavioural analysis start doing the heavy lifting.
Variants are the easy part. The harder question is why organisations that already did this work still go down.
Mistakes That Leave Slowloris Protection Incomplete
Most Slowloris incidents at organisations that already invested in security come from configuration gaps rather than missing products. The controls exist, and something in the path around them was never closed.
- Trusting the server’s reputation instead of its configuration. An event driven server without timeouts is still a server without timeouts.
- Setting a header timeout and forgetting the body timeout, which leaves the slow POST variant fully available.
- Leaving the origin reachable on its public address after adopting an edge network, so every edge control can be bypassed in one hop.
- Alerting on bandwidth and request rate only, so the one metric that moves during the attack has no threshold attached to it.
- Applying a per IP connection cap so aggressive that mobile carrier NAT ranges and corporate proxies get blocked alongside the attacker.
- Testing once at deployment and never again, while MPM changes, container migrations and library upgrades silently reset the defaults.
The NAT point deserves attention because it is where over correction bites. A single mobile operator gateway can legitimately present hundreds of users behind one address, so a cap of 20 connections per IP will generate support tickets. Combining connection caps with client fingerprinting rather than relying on address alone avoids that trade off.
Place this inside the broader plan rather than treating it as a one off. The same layered thinking behind general DDoS mitigation techniques applies here, with one adjustment: the capacity axis that dominates flood planning is nearly irrelevant, and the state management axis is everything.
Availability work compounds. Teams that already have a tested plan to prevent website downtime tend to catch slow HTTP attacks quickly, because the monitoring habits and the escalation path are already in place before the first held socket arrives.
Final Thought on Slowloris Attack
Slowloris endures because it attacks an assumption rather than a flaw. HTTP was designed to be patient with slow clients, and every server that honours that patience without a deadline inherits the risk. The fix is boring. Decide how long a client may take to finish a request, enforce it, and apply the same rule to bodies and responses as to headers.
Treat capacity and correctness as separate problems. Adding workers delays the failure and hides the cause, while a header completion deadline removes the attack outright for a single source. Layer an edge that terminates connections on top of that, and a distributed version loses its leverage too.
Practical next step: confirm your read timeouts are actually loaded rather than merely available, add the ratio of open connections to requests per second to your primary dashboard, and run a controlled slow HTTP test against staging this quarter. Those three actions cover the gap that most incident reports describe.
Frequently Asked Questions About Slowloris Attack
Is Slowloris a DoS or a DDoS attack?
Slowloris is a denial of service attack in its original form, because a single machine holds enough connections to exhaust a thread based server. It becomes a distributed attack when the same technique runs from many hosts at once, and at that point per source connection limits stop being sufficient on their own.
Does nginx stop Slowloris attacks automatically?
Not automatically, though it resists them far better than a thread per connection server. The event driven architecture means held sockets do not consume a worker each, but every connection still uses a file descriptor. Setting client_header_timeout, client_body_timeout and a limit_conn rule per address is what turns resistance into protection.
How many connections does a Slowloris attack need?
Enough to reach the server’s concurrency ceiling, which on a default Apache prefork installation means 256 simultaneous requests. Larger configurations need proportionally more, and event driven servers need far more, but the target number is always the documented worker or descriptor limit rather than a fixed figure.
Can a firewall block a Slowloris attack?
A traditional network firewall usually cannot, because every packet is valid and the request rate stays low. Blocking requires something that understands HTTP request state or tracks connection counts per client, which is why the effective controls live in the web server configuration and in application layer filtering at the edge.