Skip to content
ThemesIonic — home
Troubleshooting

WordPress Malware Removal

Removing malware is the easy half. The half people skip is proving it is gone, and every scanner type is blind to something the others catch.

Updated 5 min read advanced

Start here: malware removal is three separate tasks, and skipping the third is why sites get reinfected. Confirm what is actually infected, replace it rather than edit it, then prove the site is clean before you make it public again. Take a full copy first, even of an infected site — it is your only way back if cleaning breaks something.

This page is about the scanning and verification mechanics. For the wider incident, including containment, credential rotation and notifying anyone affected, work through how to fix a hacked WordPress site alongside it.

First, confirm it is malware

Several ordinary faults look like an infection. Check before you start deleting files:

Symptom Could also be
Site redirects somewhere unexpected A misconfigured site URL, or a plugin's own redirect setting
Unfamiliar files in wp-content A caching, backup or optimisation plugin's working directory
Browser shows a warning An expired certificate or mixed content, not malicious code
Scanner flags a theme file A false positive on minified or obfuscated legitimate code
Admin is slow and unfamiliar cron jobs exist A plugin scheduling its own tasks

Two signals are close to conclusive: core files that differ from the official release, and PHP files inside wp-content/uploads/. Nothing legitimate needs to execute from the uploads directory.

The scanner types, and what each one misses

No single scanner is sufficient, because they work on different evidence.

Integrity comparison. Downloads the official copy of your WordPress version and diffs your files against it. Excellent for core, and effectively definitive there. Blind to everything in themes, plugins and the database, because it has nothing to compare those against.

Signature scanning. Matches file contents against known malware patterns. Catches commodity infections quickly. Misses anything newly written or specifically obfuscated, and produces false positives on legitimate minified code.

Remote scanning. Fetches your pages as a visitor, sometimes as a search engine crawler, and looks at the rendered output. This is the only type that catches cloaked injections that hide from logged-in users, which is exactly how SEO spam usually behaves. It cannot see anything on disk.

Host-level scanning. Runs across the whole account, outside WordPress. Valuable because it sees sibling sites in the same account, a common reinfection route that every in-WordPress scanner is structurally unable to detect.

Run an integrity check and a remote scan at minimum. If your host offers an account-level scan, ask for the report rather than guessing.

Look where it actually hides

Signature scanners find the obvious cases. These are the places worth checking by hand:

# PHP anywhere it has no business existing.
find wp-content/uploads -type f \( -name '*.php' -o -name '*.phtml' \)

# Files changed recently, ignoring normal upload churn.
find . -type f -name '*.php' -mtime -14 -not -path './wp-content/uploads/*'

# Fake plugin directories: a single file, no readme, recent timestamp.
find wp-content/plugins -maxdepth 1 -type d -newermt '30 days ago'

In the database, three places matter and scanners often ignore all of them:

  • wp_options. Injected script tags in widget or theme option rows, and scheduled tasks under cron that re-download payloads.
  • wp_users and wp_usermeta. Administrator accounts you did not create, or an existing account quietly promoted.
  • wp_posts. Script tags or hidden link blocks appended to post content, usually across many rows at once.

Query the options table directly rather than trusting the admin screens, which the malware may be filtering. If the database itself is damaged rather than injected, that is a different job — see how to repair a WordPress database.

Replace, do not edit

Editing malware out of a file is guesswork about what else was changed. Replacement is verifiable:

  1. Core. Delete wp-admin and wp-includes, then unpack a fresh download of the same version. Delete first, never merge, or injected extra files survive. Confirm the version with how to check your WordPress version.
  2. Plugins and themes. Delete each one and reinstall from the repository or the vendor. Anything you cannot obtain a clean copy of comes out permanently — that includes pirated extensions, which are the infection in a large share of cases.
  3. Uploads. Keep the media, remove the executables. Do not delete this directory.
  4. Root files. Compare index.php, .htaccess and wp-config.php against references. Injections at the top of index.php and in .htaccess rewrite rules are classic. What belongs in the config file is in wp-config.php explained.

Do this work on a copy where you can, so a broken clean-up does not extend the outage.

Verify, properly

This is the step that decides whether you are done or merely finished cleaning.

  • Re-run the integrity check. Core should now diff clean against the official release.
  • Re-run the remote scan, as a crawler user agent. Cloaked spam only appears to search engines, so a scan as a normal browser proves nothing about it.
  • Fetch a page as Googlebot through Search Console's URL inspection and read the rendered HTML. Compare against what you see logged out in a private window.
  • Search your own site on Google with a site: query and look for pages you never published. Removal requests are covered in why a site is not showing in Google.
  • Watch file integrity for two weeks. Reinfection is fast. A file changing again is the proof that a backdoor survived.
  • Check the logs around the earliest modification time you found. If you cannot name the entry point, assume it is still open.

Only after this should the site come back to full visibility and any host suspension be appealed.

Common mistakes

  • Restoring a backup and stopping there. If the backup predates the compromise but the vulnerable plugin is still installed, the site is reinfected on the same route. Backups are covered in how to back up a WordPress site.
  • Cleaning one site on a shared account. The neighbour reinfects it. Clean all of them, or move the site to its own account.
  • Deleting the backup of the infected state. It is your evidence and your rollback.
  • Trusting one scanner's all-clear. Each type is blind to a category of infection.
  • Leaving credentials alone. Passwords, database user, hosting, SFTP and the salts all rotate, or the attacker simply logs back in.
  • Skipping the update afterwards. The fix for a vulnerable extension is the update, applied per updating WordPress plugins safely. Monitoring is not a substitute, as choosing a WordPress security plugin sets out.

Once the site is verifiably clean, work through the WordPress security checklist so the same route is closed for good.

Frequently asked

Partly. Plugins reliably restore modified core files, because a known-good copy exists to compare against. Injected code in a theme, a plugin or the database usually needs manual replacement, and no scanner finds every backdoor.
A backdoor survived, or the entry point is still open. A single leftover file that accepts remote code reinfects the site within hours, which is why replacement beats editing and why the vulnerability must be closed in the same session.
Often yes for a store, a site holding personal data, or any case where the compromise has recurred. Their advantage is a clean-file corpus and practice at finding backdoors, not a secret tool.

Related guides