We get asked about protecting WordPress login and XML-RPC from abuse more than almost anything else, so here is the long answer.
Testing in production, safely
Every rule starts in log mode. We replay the previous seven days of traffic through it and show exactly which requests it would have affected before anyone can promote it to challenge or block.
This one feature has prevented more incidents than any detection we have ever shipped.
What actually happens during a flood
The first thing to fail during a layer 7 flood is almost never bandwidth. It is connection slots, worker processes or database connections on the origin — resources measured in hundreds or thousands, not gigabits. An attacker who can make each request expensive only needs a few thousand requests per second.
That is why we score requests before they are proxied. By the time a request reaches your origin, it has been attributed to a client, compared against that client’s history and weighed against the current load on the route it targets.
What we got wrong
Our first version challenged too eagerly on mobile networks, where thousands of real users share a handful of carrier-grade NAT addresses. Reputation that is shared is reputation that is noisy.
We now weight fingerprint consistency and session behaviour far more heavily than IP reputation for traffic from known mobile carrier ranges.
Challenges beat blocks
Blocking lists go stale within minutes when attackers rotate through residential proxies. Proof-of-work does not care where a request comes from; it only cares whether the client is willing to pay the cost.
For a real browser that cost is a few hundred milliseconds, once per session. For a botnet sending a million requests a minute it is a million puzzles a minute — and at that point the attack stops being cheap.
Measuring success
We track three numbers for every incident: time to mitigation, the share of attack traffic that reached the origin, and the share of legitimate traffic that was challenged. The first should be under a second, the second under 0.1% and the third under 1%.
Those numbers go into every incident report, and they are the same numbers we are measured against in our SLA.
The numbers
Across the last quarter, 71% of challenged clients never attempted a solution, 24% solved one challenge and then behaved normally, and 5% solved challenges repeatedly while continuing to attack — the last group is where analysts spend their time.
Median added latency for legitimate visitors that were challenged was 280 ms on desktop and 410 ms on mid-range Android devices.
We will follow up with the numbers from the next quarter.
Thanks — sharing this with our on-call team.
How does the proof-of-work challenge behave on older Android devices? Any numbers below Android 10?
Carpet bombing is nasty. Good to see a clear explanation of it.
Good question. We will cover that in a follow-up post.
Great write-up. We saw almost the same pattern on our login endpoint last month.
Solid runbook advice. The DNS-at-2am point hit home.
Machine-readable ranges are at /ips.json and via the API.
Thanks — sharing this with our on-call team.
Do you publish the edge IP ranges in a machine-readable format?
Machine-readable ranges are at /ips.json and via the API.
We had the exact false-positive issue with CGNAT carriers. The weighting change makes sense.