How to Clean a Hacked WordPress Website with WP-CLI

In this article, I am writing down my exact process of how I handled a malicious website hack and how to automate the whole process. For this particular case, one of my client websites had been hacked, and a malicious script was all over the codebase.

Previously I would have tried to remove the malicious scripts one by one or with some kind of $ grep command from the shell, while I could have done that fairly faster than my approach here, it would not be likely that any of the future hacks to WP sites would have any use of my manual approach to solving it. So here’s how I used some Linux commands and WP-CLI to clean up the WP directory, re-install the core and plugin files in less than a few minutes.

Before executing any scripts be sure to make a backup of your whole WordPress root directory, this is very important!


  • wp-cli.
  • ssh access to your hosting account.
  • basic shell scripting knowledge.

Install WP-CLI

I will not go into specific details on how to setup WP-CLI, but here’s a quick guide from the official handbook. Having this installed is essential to being able to replicate what I did to clean up the hack.

Cleaning up the Install

In the section, I break down all the shell commands we need to execute, it’s best to execute all of them at once so that we minimize the downtime of the website. Another thing that would be good to do is to set up a server redirect preferably from the .htaccess file (if you are running apache) or similar to a maintenance page, it’s pretty easy to do on your own if needed.

The first thing is to clean up the admin and includes directories. Before that, we just need to login to the server via ssh and make sure that the current path is the root of the WordPress install.

$ rm -rf wp-admin && rm -rf wp-includes

Sometimes the root of the install also has a number of malicious script files, so it’s good to clean that up entirely leaving only known files that are required by WordPress like wp-config.php, .httaccess, php_errorlog, etc.

$ find . -maxdepth 1 -type f ! \( -iname "wp-config.php" -or -iname ".htaccess" -or -iname "php_errorlog" \) -exec rm -f {} +

Remove all malicious or unknown directories from the wp root, excluding wp folders or other server folders.

$ find . -maxdepth 1 -type d ! \( -iname ".*" -or -iname "cgi-bin" -or -iname "wp-admin" -or -iname "wp-content" -or -iname "wp-includes" -or -iname "staging2" \) -exec rm -rf {} +

Now we can safely download the latest wp core files, just be sure to change to the locale and version to the one that you need for your wp install. I used the latest build as that is in most cases the best thing.

$ wp core download --force --skip-content --locale=en_US --version=latest

Here are all the commands aggregated into a single line:

$ rm -rf wp-admin && rm -rf wp-includes &&
find . -maxdepth 1 -type f ! \( -iname "wp-config.php" -or -iname ".htaccess" -or -iname "php_errorlog" \) -exec rm -f {} + && 
wp core download --force --skip-content --locale=en_US --version=latest &&
find . -maxdepth 1 -type d ! \( -iname ".*" -or -iname "cgi-bin" -or -iname "wp-admin" -or -iname "wp-content" -or -iname "wp-includes" -or -iname "staging2" \) -exec rm -rf {} +

Easy way to verify the WordPress core integrity (verify the core is intact):

$ wp core verify-checksums

Cleaning up the Plugins

We can use the following command to get a list of all active plugins on the site.

$ wp plugin list --status=active

Now that we can see the list of all active plugins, we need to find a way to re-install and clean up each of them, thankfully wp-cli has a command just for that.

$ wp plugin install plugin-dirname --force

The –force keyword will overwrite any installed version of the plugin, without prompting for confirmation, this is exactly what we want to be able to override any infected plugin files.

Another thing that would make things easier for us is if we could have all the plugin names automatically inserted into that command, which is fairly easy, we just need to find and read the directory names from the shell, this is the command that I wrote for that:

$ find wp-content/plugins/. -maxdepth 1 -type d ! \( -iname ".*" \) -printf '%f '

Now let’s sum all the plugin updates into a single command:

$ wp plugin install $(find wp-content/plugins/. -maxdepth 1 -type d ! \( -iname ".*" \) -printf '%f ') --force

That should be it, you can now verify that your website works as it should!

Feel free to post a comment with any suggestions that you might have, I am happy to hear some feedback on the above!

References I used in writing the above guide:


Leave a Reply

Your email address will not be published. Required fields are marked *