Spam pages in Google results, redirects to scam sites, a “This site may be hacked” warning, or a host abuse report: WordPress sites get hacked mostly through outdated plugins and themes and weak or reused admin passwords. On your own VPS you have full access to clean it up properly. This guide walks through it.

If you see signs that the attacker got root on the server, not just into WordPress, rebuild the server instead. See detect a compromised server.

1. Contain and back up

  • Put the site in maintenance mode, or block public access temporarily (allow only your IP in Nginx).
  • Back up the infected site (files and database) before changing anything. You may need it for analysis, or to recover content.
tar -czf /root/hacked-site-$(date +%F).tar.gz -C /var/www example.com
wp db export /root/hacked-db-$(date +%F).sql --path=/var/www/example.com/public
  • Change the hosting, SSH and database passwords from a clean computer.

2. Find what was changed

Recently modified PHP files:

cd /var/www/example.com/public
find . -name '*.php' -mtime -14 -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort -r | head -50

PHP files where none should exist:

find wp-content/uploads -name '*.php'

Typical malicious code patterns:

grep -rlE 'eval\(base64_decode|eval\(gzinflate|str_rot13|assert\(\$_(POST|GET|REQUEST)|preg_replace\(.*/e|\$_COOKIE\[.{1,40}\]\(' --include=*.php . | head -50

Also check .htaccess files (redirect rules), wp-config.php (injected includes at the top), and index.php files in theme and plugin folders.

3. Verify core, plugins and themes against originals

WP-CLI compares files with the official checksums:

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

Any file reported as modified, or “should not exist”, in core or plugins from wordpress.org is suspicious. See WP-CLI.

4. Replace code with clean copies

Don’t edit infected files line by line. Replace them.

WordPress core:

wp core download --force --skip-content

This overwrites wp-admin/ and wp-includes/ and the root files, but not wp-config.php or wp-content/. Afterwards, delete unknown extra files in the root (compare against a fresh download).

Plugins and themes: delete and reinstall each from the official source:

wp plugin list
wp plugin install akismet --force

Remove plugins and themes you don’t use. Premium plugins: download fresh copies from the vendor. Nulled (pirated) plugins are a very common infection source. Never use them.

Uploads: remove any .php (and .phtml, .phar) files under wp-content/uploads, then block PHP execution there:

location ~* /wp-content/uploads/.*\.(php|phtml|phar)$ { deny all; }

wp-config.php: inspect it manually, compare it with wp-config-sample.php, and remove anything unusual.

5. Clean the database

Look for injected scripts and spam:

wp db search '<script' --all-tables --format=count
wp db search 'eval(' --all-tables
wp option get siteurl; wp option get home      # redirects often change these

Check the wp_options rows for unexpected autoloaded entries, and wp_posts for injected <script> or iframe tags. Remove spam posts and pages.

6. Users and access

wp user list --role=administrator

Delete unknown administrators. Reset all admin passwords:

wp user update [email protected] --user_pass='a-new-long-password'

Then rotate the security keys and salts, which logs out every session:

wp config shuffle-salts

Change the database password (in MySQL and in wp-config.php) and any API keys stored in plugins (SMTP, payment, CDN).

7. Check for other persistence

  • Cron jobs for the web user: sudo crontab -l -u www-data.
  • WordPress cron events: wp cron event list (look for unknown hooks).
  • Other sites on the same server, since infections spread across sites sharing a user.
  • Server-level: unknown processes running as www-data. See detect a compromised server.

8. Bring it back online and monitor

  • Update everything: wp core update && wp plugin update --all && wp theme update --all.
  • Request a review in Google Search Console if the site was flagged.
  • Monitor: file integrity (see AIDE), uptime and content checks, and access logs for repeated requests to removed shells.

Prevent reinfection

  • Keep plugins few, updated and from reputable sources. Enable automatic updates where safe.
  • Strong passwords plus 2FA for admins. Limit login attempts. See Fail2Ban for WordPress.
  • Correct file ownership and permissions: code not writable by the PHP user where possible.
  • One site, one PHP-FPM pool and system user, so a hacked site can’t infect the others. See PHP-FPM tuning.
  • A WAF in front. See WAF explained.
  • Daily off-server backups, so the next time you can simply restore a clean copy.

See the full WordPress hardening guide.

Quick reference

Task Command
Recently changed PHP find . -name '*.php' -mtime -14
PHP in uploads find wp-content/uploads -name '*.php'
Verify core wp core verify-checksums
Verify plugins wp plugin verify-checksums --all
Reinstall core wp core download --force --skip-content
List admins wp user list --role=administrator
New salts wp config shuffle-salts

Related: ClamAV and WordPress on a VPS.

  • WordPress
  • Security
  • Malware