A hacked WordPress site usually gets cleaned twice. The first time, someone deletes the obvious files, updates the plugins, and changes the admin password, and the site looks fine for a week or two. Then the redirects come back, or the spam pages reappear in Google, and the second cleanup is the one that finds the thing the first one missed. This post is about doing it once. The order matters more than any particular tool, because the attacker’s whole plan is that you’ll fix the symptom and leave the door open.
Quick answer: Take a full copy of the site as it is, for evidence. Work out how they got in before you clean anything. Then replace WordPress core, every plugin, and every theme with fresh copies from source, go through uploads and mu-plugins for PHP files, check the database for injected scripts and unknown admin users, and clear rogue cron entries. Rotate every credential the site touches, including the salts in wp-config. Only then harden and ask Google for a review. Skip the “how they got in” step and you’ll be doing this again.
Why does the site keep getting reinfected?
Because the cleanup removed what the attacker did and left how they did it. A typical compromise leaves several things behind on purpose: a small PHP file in the uploads folder that accepts commands, a modified theme file that re-downloads the payload, an extra administrator account with an innocuous name, and a scheduled task in the WordPress cron table that recreates all of the above if they go missing. Remove three of the four and the fourth rebuilds the rest overnight. We’ve also seen, more than once, a site cleaned thoroughly and reinfected within days because a second site on the same hosting account was never looked at, and the two share a filesystem. If you’ve already had the redirect variety, our post on checking the mu-plugins folder first covers that particular hiding place in detail.
The other reason is that the original entry point is still there. An outdated plugin with a known vulnerability, a password reused from a breached service, or a hosting control panel login that was never changed will let them straight back in regardless of how clean the files are.
What should you do before touching anything?
Take a complete copy: files and database, as they are, infected. It feels wrong, but you’ll want it. It lets you compare before and after, it’s evidence if the incident becomes an insurance or legal matter, and it means that if the cleanup goes badly you haven’t lost anything that wasn’t already lost. Put it somewhere off the server.
Then put the site in maintenance mode or behind a password at the web server level so visitors stop being served malware while you work, and stop the search engines seeing the spam pages. Note the date and time you first noticed the problem, because file modification times from around then are your best lead on what was changed.
How do you find the way in?
Look at the access logs for the days before the modification times you found. You’re looking for POST requests to files that shouldn’t accept them (anything in wp-content/uploads, odd filenames in the theme folder), repeated login attempts followed by a success, and requests to known-vulnerable plugin endpoints. Compare the plugin list against the vulnerability databases; if a plugin on the site had a published exploit in the weeks before the compromise, you’ve very likely found it. Check the hosting account’s login history too, and email accounts on the same domain, because a phished hosting password bypasses WordPress entirely.
You won’t always get a definite answer. When the logs have rotated or the host doesn’t keep them, the practical response is to treat every plausible entry point as the real one: update or remove every plugin, rotate every password, and turn on two-factor for anything that supports it. That’s more work than finding the one cause, and it’s the honest alternative to guessing.
What is the cleanup order?
- Reinstall WordPress core from a fresh download, replacing wp-admin and wp-includes entirely. Keep wp-config.php and wp-content, but read wp-config line by line; injected code likes to sit at the very bottom, after a long run of blank lines.
- Delete and reinstall every plugin and theme from its official source rather than updating in place. Delete anything you don’t recognise or don’t use. Anything premium or custom that can’t be redownloaded, diff against your last clean backup.
- Search wp-content/uploads for any file ending in .php, .phtml, or .ico that contains PHP. There should be none. Do the same in mu-plugins, and check for .htaccess files inside subfolders you didn’t create.
- In the database, look at wp_options for unfamiliar entries containing script tags or base64 strings, check wp_users for accounts you didn’t create (and wp_usermeta for capabilities you didn’t grant), and search wp_posts for injected iframes and script tags. Look at the cron option for scheduled events with names you don’t recognise.
- Check the root .htaccess and any index.php at the account level, not only inside the WordPress folder.
- Rotate everything: every WordPress user’s password, the database password in wp-config, the salts in wp-config (generate new ones from the WordPress API page), FTP and SFTP logins, hosting control panel, any API keys stored in plugin settings (payment gateways, email services, backup services), and the email accounts on the domain.
- Run a scanner (Wordfence’s or the host’s) as a final check, not as the cleanup itself. Scanners find known signatures and miss custom backdoors, which is why they’re the last step.
What does hardening look like afterwards?
Update everything and keep it updated, which is the unglamorous core of it; most compromises we see involve a plugin that had a fix available for months. Remove plugins you don’t use rather than leaving them deactivated, since deactivated code can still be reachable. Turn on two-factor authentication for every administrator. Add DISALLOW_FILE_EDIT to wp-config so the theme and plugin editors are unavailable. Set file permissions so the web server can write to uploads and nowhere else. Put the site behind a web application firewall, either the host’s or a service like Cloudflare, so common exploit attempts never reach PHP. And if the site earns money, get a maintenance arrangement in place; our website maintenance guide sets out what that should include and cost, and a large part of its value is that updates stop being something that happens when someone remembers.
If Google flagged the site, request a review in Search Console once you’re confident it’s clean, and expect a few days. If the site was sending spam, check the domain against the common blocklists and request delisting where needed.
Sites that have been compromised and cleaned are also often slow afterwards, because leftover cron jobs and bloated option tables don’t announce themselves. Our post on why a WordPress site is slow covers what to check.
If you’d rather hand the whole thing over, incident cleanup is part of what we do under solutions and improvements, and it starts with the evidence copy before anything else gets touched.
Frequently asked questions
Can I restore a backup instead of cleaning?
If you have a backup from before the compromise and you know when the compromise happened, yes, and it’s often faster. You still need to find and close the entry point, or the restored site gets hit the same way. Backups taken after the compromise contain the backdoors, which is why a daily backup with short retention isn’t much help here.
Will changing passwords fix it?
No, on its own. Passwords close one door. Backdoor files, rogue admin accounts, and cron entries don’t need passwords, and they’re what reinfects the site after a password-only cleanup.
How do I know if the hosting account itself was compromised?
Check the hosting panel’s login history and look for files outside the WordPress folder that you didn’t put there. If another site on the same account is also infected, assume the account was the way in and rotate the panel password and any SSH keys.
Should I tell my customers?
If any customer data could have been accessed, yes, and depending on where you and they are, you may be legally required to. If the site is a brochure with a contact form, the exposure is usually the form submissions. Talk to whoever handles your legal and insurance questions before deciding it was nothing.
Is a security plugin enough to prevent this?
It helps, mostly by blocking known attack patterns and brute-force logins. It doesn’t replace updates, two-factor, and removing unused plugins. Most sites we clean had a security plugin installed.
How long does a proper cleanup take?
A few hours for a small site with good logs and a recent clean backup, and a day or two for a larger site or one with no backup and rotated logs. The evidence copy and the entry-point investigation are the parts people skip to save time, and they’re the parts that prevent doing it twice.