One Cloudflare WAF Rule Blocked 265,000 Spam Requests in 24 Hours
A 5-Minute Cloudflare WAF Rule That Blocked Hundreds of Thousands of Spam Requests
Introduction
A live B2B e-commerce platform running on Rails was hit by a coordinated bot attack in early April. The bots crafted URLs with repeated brand names stretching over 1000 characters—each request forcing a full Rails page render and consuming critical server resources. Combined with a Redis out-of-memory event, the platform went down.
The solution wasn't expensive infrastructure. It was a five-minute Cloudflare WAF rule deployed from the dashboard. This rule blocked hundreds of thousands of malicious requests in the first 24 hours, costing nothing to maintain.
Here's what happened, what the traditional defenses missed, and how a simple WAF rule became the most effective fix.
The Attack Pattern
The bot farm was sending high-volume requests with deliberately inflated URLs:
GET /products/brand-brand-brand-brand-[...repeated dozens of times...]?filter=x&sort=y
The URLs were:
- Syntactically valid — They didn't violate HTTP spec or Rails routing rules
- Computationally expensive — Each one triggered a full Rails request cycle: routing, controller instantiation, database queries, HTML rendering
- Distributed — Sent from thousands of residential IPs, making per-IP rate limiting ineffective
- Persistent — Continued long enough to fill the worker queue and trigger memory pressure on Redis
This is a brute-force attack on server resources, not a vulnerability exploit. It works because legitimate e-commerce applications need to handle complex URLs (search filters, nested parameters, pagination). An attacker just weaponizes that flexibility.
Why Server-Side Defenses Failed
The ops team had three layers of protection already in place:
Nginx Rate Limiting
Configured with limit_req zones to allow N requests per IP per second. Problem: the bot farm was using residential IPs, likely thousands of them, rotating frequently. Each individual IP looked like legitimate traffic. The rate limiter never saw a per-IP spike.
Nginx GeoIP Whitelist
Restricted traffic to whitelisted countries only. Problem: residential-IP botnets span across allowed regions. A request from a US residential proxy with a legitimate user agent passed through.
Nginx Bad-Bot Blocker
Community-maintained list of known bad user agents and suspicious headers. Problem: the bot farm either spoofed common user agents (Chrome, Safari, mobile browsers) or omitted user-agent headers entirely. Legitimate-looking requests got through.
All three defenses were correctly configured. They just didn't catch an attack that:
- Used technically valid HTTP
- Came from IPs in whitelisted geographic regions
- Carried legitimate-looking (or missing) user-agent headers
This is the pattern: your defenses are built to stop the last attack. The next one finds the gaps you didn't know existed.
The WAF Solution
When the platform went down, the ops team opened Cloudflare's WAF dashboard and wrote a single rule:
len(http.request.uri) gt 500 and not starts_with(http.request.uri.path, "/admin")
In English: Block any request where the full URI exceeds 500 characters, except requests to paths starting with /admin.
Action: Block
Deploy time: Under 1 minute via Cloudflare dashboard
Cost: $0 (free plan)
Result in first 24 hours: Hundreds of thousands of blocked requests.
The rule operates at Cloudflare's edge, before the request reaches your origin server. It evaluates in microseconds, scales to millions of requests per second, and doesn't require any code changes or server-side configuration.
The /Admin Exception: A Real-World Lesson
The first deployment didn't include the /admin exception. Within an hour, internal support tickets arrived: "Search in the admin panel is broken."
The issue: legitimate admin searches can generate URLs over 500 characters when stacking filters:
/admin/orders?created_after=2026-04-01&created_before=2026-04-15&brand_id=12&sku_ids=456,789,1012&sort_by=created_desc&page=1
Add a few more filters or a longer product name, and you exceed 500 characters. The WAF rule was blocking legitimate internal operations.
The fix: not starts_with(http.request.uri.path, "/admin") exempted the admin panel. Redeployed in under a minute. Internal tools came back online.
Key lesson: WAF rules are blunt instruments. They're fast and scale infinitely, but you write them for the attack you see, then immediately verify they don't break legitimate flows. The first 30 minutes of a new WAF rule should include testing your most complex user journeys.
The Complete Fix Stack
The WAF rule was the circuit-breaker, but an outage of this severity meant the entire infrastructure got reviewed:
1. Nginx IP Range Block
Once the attack pattern was traced to a specific /16 IP range from the bot farm's network, the team added a direct deny in Nginx:
deny [bot-farm-ip-range]; # Block the /16 range
This is redundant (Cloudflare WAF is already blocking them), but provides defense-in-depth. If someone re-routes through a different Cloudflare edge location, Nginx still says no.
2. Passenger Worker Pool Right-Sizing
Passenger was configured to spawn workers aggressively under load. During the attack, it was spawning 30+ concurrent workers, each consuming 50-80MB of RAM. A load test revealed peak legitimate traffic needed 8 workers.
# passenger_max_pool_size: 8
This eliminated the cascade of memory starvation that led to Redis OOM.
3. Redis Maxmemory + Eviction Policy
The Redis instance had no memory limit and no eviction policy. Under attack, it consumed memory until the system OOM-killer intervened.
maxmemory 4gb
maxmemory-policy allkeys-lru
Now Redis operates as a proper cache, evicting least-recently-used keys when memory is full.
4. Cron Health-Check Loop
A cron job checked Passenger health every 5 seconds and restarted it on stalls. Under the bot attack, Passenger was legitimately stalled (queued requests), the cron detected a stall, and restarted the process. This 30-second restart window filled the request queue further, triggering another restart. A self-perpetuating failure loop.
Fix: increased health-check interval to 30 seconds and added threshold-based restart logic (only restart if queued requests exceed a limit).
Why This Attack Pattern Is Universal
Long-URI attacks aren't exotic. They work because they exploit a real tension in web infrastructure:
Your application must be flexible. It handles complex searches, nested filters, advanced sorting. You can't reject all URIs over 500 characters without breaking legitimate features.
Your server resources are finite. You have limited worker capacity, memory, and CPU.
Your first defense is your application server. By the time Nginx sees a request, it's already consumed network bandwidth, TLS handshake overhead, and routing logic.
A WAF moves the decision to the edge—before any of that happens. It's coarse-grained (no semantic analysis), but it's fast. Cloudflare's WAF blocks millions of requests per second with microsecond latency.
Bot farms use this attack because it works. They're not sophisticated. They're just patient and have access to residential IP networks. If your application is public-facing and handles search or filtering, you're exposed.
FAQ
Q: Isn't a 500-character limit too strict? What about legitimate long URLs?
A: Depends on your application. E-commerce sites hosting product search or filtering can sometimes legitimately generate URLs over 500 chars. That's why the rule should have exceptions for known long-URL paths (like /admin, /api/v2/search). Test before deploying. For most applications, 500 chars covers 99%+ of legitimate traffic.
Q: What if the bot farm adjusts their URLs to be under 500 characters?
A: They can. Then you need a different rule. Maybe you block based on repeated parameters, missing headers, or behavioral patterns (10 requests per second from the same IP). The point of the WAF is rapid iteration. Try a rule, measure results, adjust in minutes. By contrast, deploying application-level fixes takes hours or days. The WAF buys you time.
Q: Does this rule work on the free Cloudflare plan?
A: Yes. Cloudflare's free plan includes WAF with limited rules. You get 5 custom rules per account. This single rule fits comfortably.
Q: What if we're not on Cloudflare? Can we do this in Nginx?
A: Partially. You can write an Nginx rule to reject long URIs at the web server level:
if ($request_uri_length > 500) {
return 431 "Request Header Fields Too Large";
}
But this runs on your origin server, consuming its resources. By the time Nginx evaluates the rule, the request has already consumed bandwidth and CPU. A WAF at the edge is always better if available.
Q: Should we block all requests over 500 characters, or use a different threshold?
A: It depends. Analyze your legitimate traffic. If 99% of real requests are under 400 characters, set it to 500 for safety margin. If your search feature generates 800-character URLs regularly, set it higher. The goal isn't a magic number—it's a simple boundary that stops obvious abuse without breaking real usage. Start conservative, measure false positives, adjust.
Key Takeaways
-
Long-URI attacks are common and low-effort. They work because web applications need flexible URL handling. An attacker just weaponizes that flexibility with volume.
-
Server-side defenses (rate limiting, GeoIP, bad-bot blockers) have gaps. Residential IP botnets can bypass per-IP rate limits, exist in whitelisted regions, and spoof legitimate user agents.
-
A WAF rule is fast, cheap, and effective. A single rule deployed in five minutes can block hundreds of thousands of requests daily. On Cloudflare free plan, it costs nothing.
-
Exempting legitimate long-URI paths is critical. Admin panels, APIs, and complex search features generate long URLs. Your WAF rule needs exceptions.
-
WAF is defense-in-depth, not a complete solution. Pair it with right-sized application servers, Redis eviction policies, and health-check tuning. One fix doesn't solve everything, but a WAF rule is the fastest first defense.
-
Test immediately after deploying a WAF rule. Run a real search, test admin functionality, verify your most complex user journeys still work. You'll find exceptions you didn't anticipate.
Kemon Digital builds AI systems that run on live e-commerce infrastructure. If you're managing a Rails, Django, or Node app handling high traffic and bot attacks, we help design defense strategies that are both resilient and fast. Get in touch.
