Anonymized real case · May 2026
When a WordPress site is seriously hacked, the question is no longer "if" it can be recovered. It's how long it takes, how much money is spent, and how much data is lost in the process. The answer varies greatly depending on who manages the cleanup.
This is the timeline of a recovery we did in 6 hours on a client's site, completely autonomously using AI. All names and identifying details have been removed; the numbers and technical sequence are real.
What happened
The site was a nautical magazine with about 200 published articles. One morning, visitors started seeing redirects to spam pages. The owner tried to access wp-admin: 500 error. The site was officially compromised.
The attack was multi-level:
- 47 PHP malware files scattered between
/public_html/,/wp-content/mu-plugins/, and/wp-includes/ - 8 mu-plugins with backdoors — these are particularly bad because WordPress loads them automatically without being in the active plugins list
.htaccessmanipulated withFilesMatchrules that allowed access only to backdoor files- wp-config.php compromised with changed DB credentials
- 6 malicious admin users created in the database (username patterns:
khubaib,sys_,wp_*) - 1,411 posts infected with obfuscated JavaScript (
_0xhex variables, ~225KB injection per post) - 18 WordPress revisions with the same injection (the attacker exploited WP autosave for persistence)
Why this case was different from the usual
Typical WordPress scanners (Wordfence, Sucuri, MalCare) look for .php files with known patterns like dynamic code-execution functions, base64 decoders, obfuscated code. This time we had:
- Files with double extensions (
.php.php) — many scanners skip the double extension because their filter looks for literal.php - JavaScript injected into post_content in the database — filesystem scanners don't look at this
- Backdoors with names disguised as legitimate plugins (e.g.,
01-mu-AtlasDrift.php,01-mu-AuroraMesh.php) - Theme Builder Divi modifications via DB row, not files — invisible to file scanners
The Timeline (6 hours total)
0:00 → 0:30 · Initial Triage Monitoring system detects HTTP 500. Automatically starts: complete backup via cPanel UAPI (58MB tarball), full DB snapshot, audit of critical findings via external probe.
0:30 → 1:30 · Filesystem Cleanup Injected PHP helper on the client via Fileman API scans recursively:
- 47 PHP files with malware patterns → quarantined with backup
.MALWARE-{ts}.bakalongside /wp-content/mu-plugins/recursive → 8 files removed (for mu-plugins, the neutralization stub must be noop, NOT halt — otherwise, WP halts at bootstrap, see separate WSOD case).htaccessrestored with a clean version
1:30 → 2:30 · DB Users Cleanup Direct SQL query:
- 6 rogue admins identified by username patterns
- Backup
wp_users+wp_usermeta+wp_posts(rows referencing those IDs) - Reassign 1,411 posts from rogue user → new admin generated (random username + 24 char password + CRM email)
- Delete rogue users + their usermeta + cleanup orphan
- Verify: query
?author=1now returns 404, sitemap users shows only new admin
2:30 → 4:00 · Post Content Cleanup SQL scan on wp_posts.post_content with 6 patterns:
- Pattern A:
<?phpliteral injection (PHP) - Pattern B:
_0x[a-f0-9]{4,8}(JavaScript obfuscation) - Pattern C: JS decoder (atob, fromCharCode, unescape)
- Pattern D: redirect chain (location.replace, window.location)
- Pattern E: post > 50KB with
<script(size anomaly) - Pattern F: WP revisions with the same patterns (DON'T skip — they're history but can be reactivated)
Cleanup:
- Cut content at the first
<scripttag → keep legit prefix - Keep tail after the last
</script>if substantial - DELETE infected WP revisions (history, not critical)
Result: 5 published posts cleaned (from 225KB → ~300 bytes each), 18 revisions canceled.
4:00 → 5:00 · Persistent Fingerprint Cleanup The step that standard scanners skip: removing the "breach leftovers" that remain in wp_options:
admin_emailset to attacker's email (intercepts password reset)new_admin_emailwith old admin pending changeauto_core_update_notifiedwith old admin emailWPLANGchanged to'en'(frontend<html lang='en'>on an Italian site)- Theme Builder with typo "Releted news" (non-native speaker mistake in Divi layout)
- Published posts with
post_content = 0 byteafter malware cleanup
5:00 → 6:00 · Visual Verification + Hardening Visual rendering check with a headless browser:
- Body inspection: home > 1KB, contains theme markers
- Multi-endpoint:
/,/wp-login.php,/wp-json/ - Cloaking test: same md5 with Chrome UA vs Googlebot
- Hardening
.htaccess: blockwp-admin/install.php,readme.html,license.txt,xmlrpc.php - Email client with report on what was done + new admin credentials
- Schedule auto-revoke credentials after 7 days
What the client didn't have to do
- Open a support ticket
- Buy a Wordfence Premium license
- Pay an external consultant for recovery
- Restore an old backup losing X days of content
- Change hosting
What you can do if you're not our client
If you manage a WP site alone:
- Check
/wp-content/mu-plugins/every month · it should contain 0-2 files from plugins you explicitly installed. All others are suspicious. - Look for files with double extensions in
/public_htmland/wp-contentwith:find . -name '.php.'(should return 0 results) - Audit admin users in wp-admin → Users → Filter "Administrator". If you see names you don't recognize or patterns like
sys_orwp_, you've already been compromised. - Check
wp_optionsvia phpMyAdmin:admin_email,new_admin_email,auto_core_update_notified. If they contain emails that aren't yours, you have a serious problem.
How WPSonar handles this
On our clients' sites, a chain like the one described above is neutralized autonomously within 6 hours from initial detection, without requiring the owner's intervention. Everything is logged in our audit trail (append-only) and the client receives a report of what happened, what we did, and what the new credentials are.
Our system scans 10 public threat intelligence sources (Patchstack, Wordfence Intelligence, Sucuri Blog, Reddit, WP Tavern, etc.) every week to update detection patterns, so similar attacks on the next client are recognized immediately.
Frequently asked questions
How long does it take to recover a hacked WordPress site?
It depends on the depth of the compromise. A multi-level attack like the one described (malware files + infected database + rogue users) typically requires 4-8 hours of technical work. With an AI-driven system operating autonomously, the complete recovery was closed in 6 hours from detection, without waiting for human intervention.
Can I recover my site without losing content?
Yes, if the cleanup is surgical instead of restoring an old backup. In the case described, the 1,411 posts were cleaned of injected JavaScript, keeping the legitimate text, and infected revisions were deleted. Restoring a backup would have lost all content published after the backup date.
How do I know if my WordPress site has hidden malware files?
Check the wp-content/mu-plugins/ folder: it should contain 0-2 files from plugins you explicitly installed. Look for files with double extensions (find . -name '.php.' should return zero results). Check admin users in wp-admin: names like sys_ or wp_ followed by random characters indicate a compromise.
Do scanners like Wordfence find all malware?
No. Standard filesystem scanners don't analyze the database content (where injected JavaScript can live in posts) and often skip files with double extensions (.php.php). A site can appear clean to a scanner and still have active malware in the database or mu-plugins.
Sources
- Patchstack vulnerability database · centralized WP CVE
- Wordfence Threat Intelligence · compromised plugin feed
- Sucuri Security Blog · case studies and malware write-ups
- WordPress.org news feed · official releases and security advisories