01 06
Overview
An independent musician’s WordPress site was showing some visitors a Chrome-branded page saying “To continue you need to update your browser”, with a Download button. Fake browser updates like this are a common way to spread password-stealing malware. In one day the server was diagnosed, scanning and cleanup tools were built for a host that couldn’t run off-the-shelf ones, every piece of the attack was found, and the site was cleaned and hardened.
02 06
Challenge
The site ran on shared hosting with no root access, an operating system past its end of life and a server antivirus with definitions almost five years old. The malware looked like ordinary code — no obfuscation, no eval(base64_decode(...)) — so signature tools missed it, and it only ran inside a Windows desktop browser, so every server-side check returned a clean page. Cleaning it also had to avoid breaking WordPress’s serialized PHP data, where editing text corrupts stored lengths.
03 06
Solution
A diagnostic script mapped what the server could and couldn’t do, then a no-root scanner in PHP and Bash added file integrity tracking, behaviour-based rules for PHP and JavaScript, ClamAV, a MalwareBazaar hash list and VirusTotal lookups, plus database and core-checksum scans. Rendering pages in headless Chrome as a Windows visitor finally triggered the overlay and exposed the whole chain: two hidden administrator accounts, a fake “security” plugin hiding them, and a script injected into the theme footer and 200 of 203 posts that loaded the fake update in a full-screen iframe. A targeted database cleaner removed only the injected blocks, never edited serialized objects and saved every original row for one-command restore. The rogue accounts and plugins were removed, credentials rotated, and the site hardened with a Content Security Policy that stopped the fake update from loading when tested against a saved infected page.
04 06
Results
The site was cleaned and hardened the same day. A final re-scan found 0 infected database rows and a single administrator, all 3,782 core files matched the official WordPress checksums, and live pages checked as a Windows visitor no longer showed the fake update. The owner got a plain-language report, and the scanner and runbooks remain in place for future maintenance.
- Injected scripts removed
- 6,283
- Infected database rows cleaned
- 1,460
- Malicious plugins & accounts removed
- 17
05 06
Key features
- Read-only server diagnostic with a Markdown report and red-flag lists
- Incremental no-root file scanner: integrity, PHP and JavaScript heuristics, hash list, ClamAV and VirusTotal
- Read-only database scan with admin audit, scheduled-task listing and live-page check
- Core verifier against wordpress.org checksums, listing files WordPress doesn’t ship
- Database cleaner with dry run, JSON backup and one-command restore
- Dashboard and CLI to review, quarantine, restore and allowlist findings
- Behaviour rules tested for false positives across about 275,000 plugin, theme and core files
- Hardening: Content Security Policy, no PHP in uploads, no dashboard file editing, hidden usernames, XML-RPC off
06 06
Development process
-
Step 1: Assess
A read-only diagnostic over SSH checked PHP capabilities, disabled functions, ClamAV, outbound network and file counts, and flagged 14 suspicious single-file plugins and a modified theme file.
-
Step 2: Build the scanner
File integrity tracking, PHP backdoor heuristics, a MalwareBazaar hash list, batched ClamAV and VirusTotal lookups, run from the command line or a password-protected dashboard.
-
Step 3: Scan database & core
Posts, options, meta, admins, scheduled tasks and code snippets were scanned read-only, and every core file was compared with the official checksums.
-
Step 4: Reproduce the attack
Headless Chrome with a Windows user agent triggered the overlay, exposing the script, its remote URL file and its cloaking rules.
-
Step 5: Clean safely
Only matching script blocks were removed and poisoned cache entries deleted, with a dry run first and every original row backed up.
-
Step 6: Harden & verify
Hardening was applied one change at a time, then the database was re-scanned and live pages re-checked as a Windows visitor.
Stack
- WordPress
- PHP
- Bash
- MySQL
- SQLite
- Apache / .htaccess
- Content Security Policy
- Headless Chrome
- ClamAV
- VirusTotal API
Live project // rekordstak.com
Visit live project (opens in a new tab)


