Skip to content
The site is hacked

Remove malware from WordPress

Why deleting the files a scanner found isn't enough, and what a thorough clean-up involves.

You need
FTP
Updated

A scanner such as Wordfence compares the WordPress files with the originals and looks for known malicious code in the files and the database. It still doesn't find everything. Code it doesn't recognise can stay behind, especially in paid plugins and custom themes, which it has no original to compare with. If you only delete what the scanner found, the attacker can come back through the code that was left behind.

A thorough clean-up means replacing everything you can with clean copies, going through what can't be replaced, and finding the security hole the attacker came in through.

Before you start

  1. Make a copy of all the files and export the database, even though everything is infected. You need the evidence to find out what happened, and the copy is all you have if something goes wrong.
  2. Check whether your host has a backup from before the attack. Restoring it can be faster than cleaning, but the security hole still has to be closed afterwards.
  3. Change the passwords for wp-admin, the hosting panel, FTP, SFTP and the database. If you change the database password, the new password also has to go in the DB_PASSWORD line in wp-config.php. Otherwise WordPress can't reach the database, and the site only shows an error message.

Clean up in wp-admin

  1. Go to Users and look for administrators you don't know. Note their user names, email addresses and when they were created, and remove their administrator role. Delete them once the clean-up is done. The date isn't shown in wp-admin. You find it in phpMyAdmin, in the user_registered column of the wp_users table.
  2. Delete unused plugins under Plugins and unused themes under Appearance → Themes.
  3. Under Plugins there may be a tab called "Must-Use". It lists the files in wp-content/mu-plugins, which always run and can't be deactivated in wp-admin. Take a close look at anything there you don't recognise.

Replace WordPress over FTP

The "Re-install version" button under Dashboard → Updates isn't enough. It overwrites the files that exist but doesn't remove new files the attacker added.

  1. Find your version number in wp-includes/version.php and download the same version from wordpress.org.
  2. Delete the wp-admin and wp-includes folders on the server and upload the new ones.
  3. Upload the root folder files from the download, overwriting the ones on the server. Then take a closer look at any file in the root folder that wasn't in the download. wp-config.php and .htaccess belong there, but read through them too and look for code that doesn't belong.

Replace plugins and themes

  1. Delete each plugin's folder in wp-content/plugins and upload a fresh copy from wordpress.org or from the vendor. Get paid plugins from your account with the vendor.
  2. Do the same with the theme. If you have a child theme or custom code, you have to read through that code yourself, because no clean copy of it exists anywhere.

Go through the rest

  • wp-content/uploads holds images and documents, but also files that plugins create, such as CSS, scripts, fonts and logs. PHP files rarely belong there. Some plugins put a short index.php in their folders, but take a closer look at every other PHP file in uploads.
  • Look for .htaccess, .user.ini and php.ini in every folder. An auto_prepend_file line runs a file before every request. Wordfence uses it for its firewall and points it to wordfence-waf.php. If it points to any other file, take a close look at that file.
  • Look for scheduled tasks you don't recognise, both cron jobs in the hosting panel and WP-Cron events in WordPress. The WP Crontrol plugin lists the WP-Cron events. Malware can register a scheduled task that reinstalls it after the clean-up.
  • Search the database with phpMyAdmin for <script, eval and base64_decode in the wp_options and wp_posts tables.

If you have SSH and WP-CLI on the server, you can check the files against the official copies on wordpress.org:

wp core verify-checksums
wp plugin verify-checksums --all

File should not exist means there is an extra file in the WordPress folders. Paid plugins can't be checked this way.

After the clean-up

  1. Change the passwords again, now that the site is clean.
  2. Change the salt keys in wp-config.php so everyone is logged out. You can get new keys from https://api.wordpress.org/secret-key/1.1/salt/. With WP-CLI, wp config shuffle-salts does the same.
  3. Update WordPress, the plugins and the themes.
  4. Check the site from the outside with Sucuri SiteCheck and Google Safe Browsing, and use WPScan to check whether any plugin has known vulnerabilities.
  5. If Google has flagged the site as dangerous, request a review in Search Console.

When you're stuck

If the malware comes back, you haven't found the security hole yet. Look for an outdated plugin, a leaked password or another infected site on the same hosting account. The server logs can show how the attacker got in, if they go back far enough, but reading them takes access to the hosting and experience with WordPress security.