The redirect was not on the server — proving it at the CDN
Two previous cleanups had found nothing because the redirect was generated by the CDN, not the website. Differential testing proved it in twelve seconds, and the audit uncovered a second, undocumented compromise.
- Client
- Creative agency, United Kingdom
- Sector
- Security
- Stack
- Cloudflare · cURL · WordPress · cPanel · Linux · DNS
- Year
- 2026
The problem
Every visitor to a client's website was being redirected to an unrelated third-party domain. Two previous cleanup attempts had gone through the files and found nothing.
They found nothing because there was nothing to find. The cause was not on the server.
Proving it
I requested the site twice. First directly from the origin server with a forced Host header, bypassing the CDN entirely. Then normally, through the CDN, twelve seconds later.
The origin returned the correct page — HTTP 200, LiteSpeed, unmodified since March. The CDN returned a 301 to the attacker's domain. Same site, same minute, one variable.
Then I ruled out caching three separate ways: a URL that had never been requested before, a path that had never existed, and the absence of the cf-cache-status header. Together those establish that the redirect was generated by the CDN's rules engine before any cache lookup — and therefore that a cache purge, the obvious next step, would achieve exactly nothing.
I certified the site and server clean: every file, the theme, mu-plugins, .htaccess, the account crontab, authorized_keys and login history, cross-referenced against three provider malware scans spanning nine months.
What else was on the account
A second website sharing the same hosting account was compromised — a domain absent from all handover documentation and never previously audited. Two payloads:
A self-replicating plugin and mu-plugin pair, where each copy rebuilds the other. Removing one silently restores it from the other, so a partial cleanup looks successful and is not. It also hides itself from the WordPress plugins screen.
A JavaScript injection using EtherHiding — storing its command-and-control address in a smart contract on the Polygon blockchain. There is no fixed domain to block, no host to notify, and no takedown to request. The address is read from a public ledger that cannot be seized.
Neither had been detected by the host's scanners: the code contains no eval and no base64, so signature-based detection has nothing to match.
I also found a backdoor from an earlier intrusion still live on the account — one the provider's own scan had flagged months before and never removed.
Outcome
Remediation required CDN dashboard access held by the client, so the deliverable was a proven diagnosis and a precise remediation path rather than a fix I applied myself.
That meant the report had to stand on its own: full methodology, every command run, and reproducible verification tests the client could execute independently. Alongside it, an evidence package — malware samples, the complete DNS zone captured before any change, cron tables and login history. I also flagged three pre-existing email misconfigurations found along the way: duplicate SPF records, an unauthorised Google Workspace entry in SPF, and DMARC left in monitor-only mode.
Why it mattered
The two prior cleanups were not incompetent. They audited the layer where website compromises normally live, found it clean, and had no way to prove a negative. What changed the outcome was a test that isolates one variable — origin versus edge — rather than a more thorough search of the same layer.
The blockchain-hosted payload is the part worth understanding for anyone running WordPress. Every remediation playbook assumes there is an attacker-controlled domain somewhere in the chain that can eventually be blocked or taken down. This one has no such domain, and the industry's default response does not apply to it.
Have a system that needs to work in production?
Tell me what's breaking — or what you're building.