How to clean a hacked WordPress site
Isolate the site, find every piece of the infection, remove it, close how it got in, then confirm it is actually gone.
A hacked WordPress site needs cleaning in a specific order: contain it, find every piece of it, remove it all at once, close the way it got in, then verify. Doing these out of order is how sites get "cleaned" three times in a month — removing what you can see while leaving behind whatever let the attacker back in.
An admin account you did not create, the site redirecting to somewhere else intermittently or only for certain visitors, unfamiliar files in wp-content, a sudden drop in search rankings, your host or browser flagging the site, or content appearing that you did not write.
Step 1: contain it
Before investigating further, limit the damage a live infection can keep doing:
- Put the site into maintenance mode or take it temporarily offline if it is actively serving malicious content to visitors.
- Change every password connected to the site immediately — WordPress admin accounts, the database user, FTP, and your control panel login. Assume all of them are known to the attacker.
- Take a backup of the site as it currently stands, infection and all, before changing anything else. This preserves evidence of what happened and gives you something to fall back on if a fix goes wrong.
Step 2: find the infection
A hack is rarely one file. Look everywhere at once:
Scan for malware
A security scanning plugin or your host's malware scanner will find known malicious code patterns automatically. See scanning your site for malware. Treat this as a starting point rather than the whole answer — scanners find known patterns, not everything.
Check for unfamiliar admin accounts
Go to Users in the dashboard and look for any account you do not recognise, particularly anything with the Administrator role. Delete anything unexplained once you have confirmed it is not a legitimate account you had simply forgotten about.
Compare files against a clean copy
WordPress core files should match the official release exactly. Download a fresh copy of the same version from wordpress.org and compare it against what is on the server — any difference in a core file is suspicious and worth investigating individually. Pay particular attention to files with recent modification dates that do not correspond to anything you changed.
Look for unfamiliar files and unexpected code
Malicious code is commonly hidden in files with names designed to look legitimate, in the uploads folder (which should never contain executable PHP at all), or appended to the start or end of otherwise normal theme and plugin files. Search for functions commonly abused for this purpose, such as eval(, base64_decode(, and gzinflate(, across the codebase — their presence is not automatically malicious, but an unexplained cluster of them in a file that should not contain any is a strong signal.
Check scheduled tasks
Look at any cron jobs configured in your control panel for anything you did not set up, since a persistent infection sometimes uses one to reintroduce itself after a manual cleanup.
Step 3: remove it, all of it
Once you have mapped out what was affected:
- Replace WordPress core, all plugins and the theme with fresh copies from their official sources rather than trying to edit infected files in place. This is faster and more reliable than surgically removing malicious code line by line.
- Keep only wp-content/uploads and the database from the compromised site, and check both of those specifically for injected content — malicious code in a database value, or a disguised PHP file sitting in the uploads folder.
- Remove every unfamiliar admin account identified in the previous step.
It is very difficult to be certain you found every altered file by inspection alone. Replacing WordPress, plugins and the theme wholesale, and keeping only your uploads and database, removes that uncertainty.
Step 4: close how it got in
Removing the infection without finding the entry point invites a repeat. The most common causes, roughly in order of likelihood:
- An outdated plugin or theme with a known vulnerability.
- A weak or reused password on an admin account.
- A nulled or pirated plugin or theme, which frequently ships with malicious code already built in.
- A compromised computer used to access the site, with saved credentials stolen directly from it.
Whichever it was, address it directly before putting the site back online. See securing a WordPress site for the full set of measures worth having in place afterwards, including two-factor authentication and login attempt limits.
Step 5: verify before calling it finished
- Run another malware scan and confirm it comes back clean.
- Check the Users list again for anything new.
- Check whether your domain has been flagged by any browser security warning, and request a review if so once you are confident the site is genuinely clean.
- Monitor the site closely for a week or two afterwards — a reinfection usually means the original entry point was not actually closed.
If this feels beyond what you can safely handle
A hack is not the moment to learn database administration under pressure. If the site holds anything valuable — customer data, an income-generating shop — it is reasonable to bring in professional help rather than working through this alone, and to get in touch with our support team for help with anything on the hosting side, including restoring from a clean backup if one exists from before the compromise.
Related reading
Updates, strong unique logins, two-factor authentication, a minimal plugin list, and backups that actually restore — in that order of importance.
How to scan your site for malwareThe practical ways to actually check your files for malicious code, and how to read the results without missing what matters.
How to reset a WordPress passwordThree ways to reset a WordPress password, from the ordinary email link to editing the database directly when nothing else works.
What to do first if your website is hackedA calm, ordered checklist for the first hour: contain it, change every credential, restore clean, then find how it got in.