Anonymized at this stage. We have not asked for attribution yet and will not publish the client’s name without it.
01 · The morning it started
The site was not down. That was the small problem.
The client reports the website is down
It was not. Overnight, while mitigating unusual traffic, we had blocked a range of IP addresses generating abnormal request volumes. One of those blocks had caught the client own office.
Confirmed and unblocked
Thirty-eight minutes to establish that, confirm the IP, and unblock it. The site was still slow, and slow looked like the whole story for about half an hour.
The real failure surfaces
The connection to the applicant tracking system had dropped and stopped syncing. The public site was still loading. Job listings still displayed. Application forms still rendered. But no new roles could be published and no applications could be actioned. Every consultant in the firm was blocked, and nothing visible on the website suggested anything was wrong.
Site stable, same business day
The cause was bot-driven DDoS and brute force traffic consuming the server resource allocation.
Next morning, confirmed
Site speed back to normal, ATS sync working. No candidate or client data was compromised. Applications submitted during the incident had been captured locally throughout and synced once the load dropped.
The client’s own summary: it “stops business.”
02 · What was happening
The order the server shed work in is the entire story.
The site was on a host where autoscaling had been deliberately switched off, a reasonable decision taken to avoid an uncapped bill during exactly this kind of event.
The consequence was that the server hit a hard resource ceiling instead of scaling, and when it did, it started shedding work. It kept the public-facing pages alive and dropped the third-party API calls first.
So the symptom everyone could see, a slow website, was the least important thing happening. The symptom nobody could see, the ATS sync silently failing, was the one costing money.
03 · The decision
Autoscaling was the faster fix and the wrong one.
Two options were on the table within hours: turn autoscaling back on, or put a security layer in front of the site.
Turning it back on meant choosing, permanently, between a potential four-figure bill during an attack and a hard ceiling that takes the ATS down. Neither is a position a business should have to hold.
The recommendation was to migrate hosting and deploy Cloudflare Pro properly, as one piece of work. The honest framing given to the client CEO was that this was a one-off cost covering migration, firewall integration and a set of rules that would let us act quickly during the next attack, because there would be a next attack.
Twelve days later the client own team flagged a fresh wave of bot registrations, the same pattern seen in the weeks before the original incident. That validated the decision to harden rather than stop at the site is stable.
04 · The work
Migration, then Cloudflare, then the things nobody expected.
Hosting migration
Traffic history pulled first: peak around 120,000 monthly visits, typical range 60,000 to 70,000. The plan was sized against the peak rather than the average.
Every DNS record inventoried before anything moved, including the MX and TXT records that break email rather than websites when they go wrong. Registrar credentials handled properly: password changed before being shared, changed again afterwards to revoke access.
The old environment was kept live and functional throughout, so if the new one had behaved unexpectedly the domain could point back and the site would be exactly as it was. The migration ran in a defined 90-minute window outside peak hours. That is our standard hosting migration process.
Cloudflare Pro deployment
Around fifteen hours across eighteen discrete tasks: DNS transfer, SSL set to Full (Strict) with TLS 1.2 minimum and HSTS, Cloudflare and OWASP managed rulesets with a false positive pass before anything moved from log to block, rate limiting on login, admin and API endpoints, custom rules covering malicious and empty user agents, sensitive file extensions, XML-RPC and suspicious URI patterns, geographic policy, cache rules with explicit bypasses, security headers, image optimization, a firewall analytics baseline, and full functional testing. The full task list is on the Cloudflare setup page.
The caching problem nobody expected
Within a week of the new infrastructure going live, candidates started reporting that job applications were failing with a security token error. The baseline was one or two reports every few months. It became six candidates over a single weekend, then more each day. The client could not reproduce it. Neither could we, initially, because we were testing logged in and caching layers serve logged-in users fresh pages.
The cause was full-page caching serving the same one-time form token to every visitor. Cache disabled on job pages at the CDN, and reports dropped sharply. Still not zero: investigation with the host revealed a second, server-level page cache, not visible anywhere in the WordPress admin. Disabled on job pages too. The next morning, no reports. A week later, one from the registration page instead. Same fix applied there, at both layers.
One isolated case remained afterwards, which turned out to be a genuinely expired token from a form left open for hours. That is WordPress security working correctly and there is no configuration that removes it. We escalated to the plugin vendor to ask whether the error message could at least be made comprehensible to a candidate, and were explicit that we would not accept a workaround that weakened the token.
The bill that would not stop growing
By summer, a different problem. The hosting plan monthly visit allowance was being exceeded every month, and the overage was being paid every month. The obvious response was to upgrade the plan. Before doing that, we measured what was consuming the allowance.
AI crawlers accounted for roughly 7,000 hits over seven days. Extrapolated, around 30,000 visits a month, billed against a plan priced by visit count, none of them a potential candidate or client.
The client asked directly whether increasing bot protection would help. The answer was no: a blanket increase catches search engine crawlers along with everything else, and for a job board, search visibility is how candidates arrive. Instead we identified the specific crawlers, presented the list with what blocking each one would cost, got written approval, then blocked by name. Two aggressive regional crawlers with no audience overlap with a UK recruitment business, and one SEO tool crawler that was repeatedly requesting pages that did not exist. That approach became our bot and AI crawler control service.
RuleSearch engines and the AI assistants that send referral traffic stayed fully accessible.
The finding that invalidated the rest
The blocks went in. The traffic barely moved. The reason was DNS: not all traffic was routing through Cloudflare, so a portion of requests were reaching the origin server without passing through a single security rule. Every rule written over the preceding months was working perfectly on the traffic it could see, which was not all of it.
The DNS change was scheduled with the client, then moved back a day at their request so more of their team would be in the office to test. It ran at 05:56 to minimize disruption. By 09:29 the same morning the client confirmed the site was fine from the office and, critically, that new roles were still pulling through from the ATS. Under four hours from cutover to verified, with no reported issues.
RuleThis is the step that gets skipped, and it silently invalidates everything upstream of it.
06 · Where it stands
The relationship continued past the security work.
Into an ongoing maintenance retainer, and into the next piece: a full audit of what the site is collecting about candidates, which turned up fourteen separate tracking and third-party components firing before anyone had consented to anything, on pages where candidates upload their CVs.
That is a different case study. Everything above is available as our WordPress security service.
07 · Honestly
What we would say about this honestly.
What went well
Contained same day, correct root cause
No data loss. The root cause was correctly identified as resource exhaustion rather than a breach, which meant the right fix was implemented rather than a panic response. The bot analysis saved a hosting upgrade that would have been permanent and would not have addressed the cause. The DNS finding caught something that would otherwise have quietly undermined months of work.
What we would do differently
The two-week traffic review was never completed
Which means the before-and-after numbers that would prove the commercial impact are still sitting in two dashboards, unclaimed. That is an unforced error. A measurement that is not reported back is a measurement that did not happen.
What we cannot claim
That this site will not be attacked again
It will. What changed is that the next time it happens, there is a measured response instead of an improvised one, and the client own team can act in the first five minutes.
The work on this page is delivered as four separate services: Cloudflare setup, bot and AI crawler control, emergency DDoS response and hosting migration, with the ongoing relationship running through maintenance.