How to clean a hacked WordPress site, step by step

How to clean a hacked WordPress site: isolate it, find backdoors, clean files and database with wp-cli, restore a clean backup, then harden it.

Workflow for cleaning a hacked WordPress site, from isolation to hardening

Key takeaways

  • Before you clean a hacked WordPress site, isolate it and back up the infected state.
  • If you have a backup from before the infection, restoring it and patching the hole is usually faster and safer than cleaning file by file.
  • Replace WordPress core, plugins and themes with official copies, then check uploads, mu-plugins, wp-config.php, .htaccess and the database.
  • Change every password and security key once the site is clean, and find and fix the way the attacker got in.

To clean a hacked WordPress site, work in order: isolate the site, back up the infected state as it is, change passwords, then choose one of two paths. If you have a clean backup from before the hack, restore it and patch the vulnerability. If not, replace WordPress core, plugins and themes with official copies, then clean the places malware likes to hide: the uploads folder, mu-plugins, wp-config.php, .htaccess and the database. Finally, change passwords again, update everything and find how the attacker got in, or the site will be reinfected within days.

This guide covers the warning signs, each step with concrete commands (for Ubuntu 24.04 and Debian 12), how to do it in ZoPanel, and how to harden the site afterwards. If the site holds customer or payment data, consider hiring a professional; this guide helps you handle the common cases yourself and know what to ask.

Signs your WordPress site has been hacked

The official WordPress documentation lists the clear indicators, and in practice we see a few more:

  • Google shows "This site may be hacked" or a red warning page.
  • Visitors from Google (especially on mobile) are redirected to gambling, pharma or scam pages, while you see nothing when you visit directly.
  • Unknown administrator accounts appear under Users.
  • A site:yourdomain.com search shows thousands of strange pages, often Japanese or designer-goods spam.
  • Your host suspends the site or reports that the server is sending spam.
  • CPU spikes, and unfamiliar PHP files appear in wp-content/uploads.
  • Visitors' antivirus software flags the site.

Modern malware often hides from administrators: it shows only to visitors from Google, only on mobile, or once per IP. A site that looks normal to you is not necessarily clean.

Step 1: Stay calm, document and isolate

Write down what you see, when, and what changed recently (new plugins, updates, new users with access). These notes help when you look for the cause.

Then isolate:

  • Turn on maintenance mode, or temporarily put the whole site (/) behind a password-protected directory.
  • If the site is sending spam, stop that account's outgoing mail for now.
  • On shared hosting, tell your provider: the infection may spread to other sites in the same account.

Step 2: Back up the infected state

It sounds backwards, but save a full copy (files and database) before you change anything. If cleaning breaks the site you have a reference; if you need to investigate, it is your evidence. Name it clearly, for example infected-2026-11-11.tar.gz, and never restore it by mistake.

cd /home/client1/domains/example.com
tar czf ~/infected-$(date +%F).tar.gz public_html
wp db export ~/infected-$(date +%F).sql --path=public_html --skip-plugins --skip-themes

--skip-plugins --skip-themes matters: wp-cli loads WordPress to run commands, and without these flags you may be executing the malware itself.

Step 3: Change passwords and end every session

Change the password for every access point: WordPress admins, SFTP/FTP, the control panel, the database, email. Generate new security keys (salts) in wp-config.php so every session, including the attacker's, is logged out:

wp config shuffle-salts --path=public_html --skip-plugins --skip-themes

List administrators and remove unknown ones (reassigning their posts to a legitimate user if needed):

wp user list --role=administrator --path=public_html --skip-plugins --skip-themes

You will change passwords once more after the site is clean, because a leftover backdoor could steal the new ones.

Step 4: Restore a clean backup or clean manually?

Situation What to do
A backup from before the infection, and you can accept losing changes since Restore, then update and patch immediately
A backup, but you are unsure when the infection started Restore files from the older backup, keep the current database after cleaning it
No clean backup Clean manually, as in Step 5
An e-commerce site with payment data Hire a professional, preserve evidence

Malware often sits quietly for weeks before it shows, so "yesterday's backup" is not necessarily clean. Run the checks below after restoring too.

Step 5: Clean WordPress piece by piece

5.1. Verify core against the official checksums

wp core verify-checksums --path=public_html

wp core verify-checksums compares core files with WordPress.org's published checksums without loading WordPress. Modified files and extra files in core folders are listed.

The safest approach is to replace core with a clean copy of the same version (keeping wp-content and wp-config.php):

VER=$(wp core version --path=public_html --skip-plugins --skip-themes)
wp core download --version="$VER" --skip-content --force --path=public_html

This overwrites files but does not delete files an attacker added to wp-admin or wp-includes. Delete those two folders first and then download, or remove the files verify-checksums reports as "should not exist".

5.2. Plugins and themes

wp plugin verify-checksums --all --path=public_html --skip-plugins --skip-themes

Plugins from WordPress.org are checked against checksums. Premium plugins and commercial themes have no public checksums: download the latest version from the developer and replace the whole folder. Delete every unused plugin and theme. "Nulled" (pirated) plugins are a very common infection source; remove them now.

5.3. Where malware hides

cd /home/client1/domains/example.com/public_html

# PHP files in uploads (WordPress never needs these)
find wp-content/uploads -type f -name "*.php"

# Must-use plugins: run automatically, not shown in the normal plugin list
ls -la wp-content/mu-plugins 2>/dev/null

# PHP files changed in the last 14 days
find . -type f -name "*.php" -mtime -14 -printf "%TY-%Tm-%Td %p\n" | sort

# Common obfuscation patterns
grep -rlE "eval\(base64_decode|gzinflate\(base64_decode|str_rot13\(" --include=*.php .

Also check wp-config.php (stray include lines at the top or bottom), .htaccess in every folder (redirects based on User-Agent or a Google Referer), and the theme's index.php, header.php, footer.php and functions.php. The grep can return false positives, since some legitimate plugins use base64; open a file before deleting it.

5.4. The database

Database malware is usually <script> tags injected into posts, widgets or theme options:

wp db search "<script" --all-tables --path=public_html --skip-plugins --skip-themes
wp db search "eval(" --all-tables --path=public_html --skip-plugins --skip-themes

Also check for unfamiliar scheduled events (wp cron event list) and the siteurl and home values in the options table. Fix them with Adminer or phpMyAdmin, and always back up the database before deleting rows.

Step 6: Update, change passwords again, harden

  1. Update WordPress core, every plugin and theme, and move to a supported PHP version.
  2. Change every password again and regenerate the salts.
  3. Turn on two-factor authentication for administrators.
  4. Disable the dashboard file editor (DISALLOW_FILE_EDIT), block PHP execution in uploads, and make wp-config.php readable only by the account.
  5. Find the cause: an unpatched plugin, a brute-forced weak password, or a local computer with a trojan stealing FTP credentials. Scan your own machine too.

If Google flagged the site, go to the Security Issues report in Google Search Console and request a review once the site is clean.

How to do it in ZoPanel

These tools are built into the panel and shorten the steps above considerably. Details are in the Security and WordPress Toolkit docs.

  • Malware scan: looks for webshells, backdoors, obfuscated code, injected JavaScript and PHP files in upload folders. Every account is scanned automatically each Sunday, and customers can click Scan now. For each finding, Quarantine moves the file out of the website to /var/lib/zopanel/quarantine/<user>/, a folder only root can read, so it cannot run, or Ignore marks a false positive.
  • WordPress tab → Security: Verify file integrity compares core and plugins with official checksums; Rotate security keys generates new salts and signs everyone out; Reset password works for any user; Apply all sets the recommended options (file editor off, PHP blocked in uploads, xmlrpc.php blocked, wp-config.php at mode 600).
  • Restore single files or folders from nightly incremental snapshots in the Snapshots (incremental) card on the Backups page, and restore databases from database backups (the current data is backed up first). Click Snapshot now to save the infected state before you clean.
  • Web application firewall (ModSecurity with the OWASP Core Rule Set): run Detect only for a few days, then switch to On (block attacks).
  • Safe updates: snapshot, update, health check and automatic rollback, so you can turn on nightly automatic updates without fear of breaking the site.

Just as important is what sits outside WordPress: each hosting account runs as its own Linux user with its own PHP pool, so an infected site cannot read other customers' files, and per-account hourly sending limits stop a hacked site from getting the server's IP blocklisted. We explain this architecture in Why a hosting control panel should never run as root.

Mistakes that lead to reinfection

  • Deleting only what the scanner flagged. There is often a second backdoor, planted precisely to survive the first cleanup.
  • Changing passwords before the cleanup and never again. A leftover backdoor can capture the new ones.
  • Reinstalling a pirated plugin. That is often how the malware got in.
  • Restoring a backup without patching. The attacker returns the same way within hours.
  • Skipping the database. The files are clean, but injected scripts in posts still redirect visitors.
  • No off-server backups. If the attacker controls the account, backups in the same account are not safe either.

Conclusion

Cleaning a hacked WordPress site is a process: isolate, preserve evidence, change passwords, restore or replace with official copies, clean the hiding places, then fix the actual vulnerability. Prevention is still cheaper: regular updates, off-server backups, per-account isolation and scheduled scans.

ZoPanel includes malware scanning, WordPress integrity checks, safe updates with rollback and nightly snapshots, all on the Free plan. See pricing, or read our guide to securing an Ubuntu VPS to harden the whole server.

Frequently asked questions

How do I know if my WordPress site is hacked?

Common signs: Google warnings, visitors from Google redirected to strange sites, unknown administrators, thousands of odd pages in site: results, PHP files in the uploads folder, or your host reporting spam from the server. Run wp core verify-checksums and a malware scan to confirm.

Can a security plugin clean the site for me?

Scanner plugins help with detection, but they run inside the same infected WordPress, where malware can interfere with them. Combine them with outside checks: wp-cli checksums, a server-level scan, and a manual look at uploads, mu-plugins and .htaccess.

Is restoring a backup enough to remove malware?

Only if the backup predates the infection and you patch the vulnerability right after restoring. Malware can sit quietly for weeks, so verify the restored site with checksums and a scan before you reopen it.

How long does Google take to remove a hacked-site warning?

Once the site is clean, request a review in the Security Issues report of Google Search Console. Timing varies case by case, and the request is rejected if Google still finds malware, so check thoroughly before submitting.

Why does my site keep getting hacked after cleaning?

Usually a backdoor was missed, the original hole (an outdated plugin, a weak password) was not fixed, or the admin's computer has a trojan stealing passwords. Check all three before calling the cleanup done.