How to Remove Malware from WordPress (Without Paying $500 to a Cleanup Service)

Quick answer: To remove WordPress malware yourself in about two hours: (1) snapshot the site, (2) put it in maintenance mode, (3) rotate every password and the eight wp-config.php salts, (4) find injected PHP files in uploads and diff core against a fresh WordPress download, (5) check the database for rogue admins and injected scripts, (6) purge every cache layer, (7) verify before going live. Pay a cleanup service only if traffic is actively hemorrhaging, you do not know SFTP or SQL, or the breach extends beyond WordPress.

Every other guide on this topic is a sales funnel. You land on the page, read three paragraphs about how malware is scary, and then the article tells you to either buy a plugin or pay someone $500 to run a cleaner you could run yourself.

This post is the actual process. If you’ve used WordPress for more than a year and know how to use SFTP, you can do this yourself in about two hours. If you can’t, the last section tells you when paying someone is the right call.

Before You Touch Anything, Snapshot the Site

Copy the whole thing. All files, the database, everything. Download it. Put it on a drive.

You probably won’t use this snapshot. You’re taking it because malware investigation is lossy. You’ll delete a file, realize later it held a clue, and not be able to get it back. The snapshot is your undo button.

Hostinger, SiteGround, Kinsta all have one-click snapshot tools. Use them. If your host doesn’t, use wp db export and an SFTP mget -R.

The snapshot is your undo button.

Put the Site in Maintenance Mode

While you work, visitors shouldn’t be hitting it. The reason isn’t privacy. It’s that the attacker likely has a mechanism that re-infects on every request. If you clean a file while the site is serving live traffic, the backdoor you missed re-writes it before you’re done.

Drop a .maintenance file in the WP root with <?php $upgrading = time(); ?>. That’ll show the default “briefly unavailable” page. Or block everyone but your IP in .htaccess.

Change Every Password, Then Every Key

Every admin password. The database user password. Your hosting account password. Your SFTP password. Any API key stored in wp-config.

Then rotate the salts in wp-config.php. Those are the eight AUTH_KEY, SECURE_AUTH_KEY, and related lines near the top of the file. If you don’t rotate them, any active session cookie the attacker captured still works after you change the password. The WordPress.org secret-key generator gives you a fresh set.

This one step stops more active infections than any scanner will. The attacker has credentials. Until you rotate, they can walk back in.

The attacker has credentials. Until you rotate the salts, they can walk back in.

Find the Malicious Files

You’re looking for three categories.

Webshells. PHP files with base64-encoded payloads, eval(), assert(), str_rot13(), or gzinflate(). They get dropped in wp-content/uploads/, inside plugin directories, sometimes the theme folder. Uploads is the biggest red flag. That folder should not contain PHP files. Ever.

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

If that command returns anything, those are your first suspects.

I’ve never seen a legitimate PHP file inside uploads. Ignore anyone who says otherwise.

Injected core files. Attackers often modify wp-load.php, wp-config.php, index.php, or files inside wp-includes/. Download a fresh copy of WordPress matching your version and diff the two.

diff -r wordpress-6.8/wp-includes/ /path/to/your/site/wp-includes/

Anything that shows up in the output shouldn’t be there. WordPress core files are byte-identical across every install of the same version.

Theme and plugin injections. These are harder to find. Attackers inject one-line backdoors into theme functions.php or random plugin files. The easiest path is to delete the theme and every plugin, then reinstall them fresh from the WordPress.org repo or your paid-plugin vendor. Your content, settings, and users live in the database. Plugin files are reinstallable.

Check the Database

Database infections are less common than file infections, but they happen. Look at:

  • The wp_users table for any admin accounts you don’t recognize
  • The wp_options table, especially active_plugins and any values that reference files you don’t have
  • Post content, via SELECT * FROM wp_posts WHERE post_content LIKE '%<script%src=%', which finds injected tracking scripts
  • The wp_posts table for posts with author IDs that don’t exist in wp_users, since orphaned content often signals a takeover

If you find a rogue admin, don’t just delete the row. Note the user ID, then check wp_usermeta for session tokens tied to that ID. Delete both.

Clear Every Cache Layer

Object cache, page cache, CDN, browser. All of them. I’ve seen cleaned sites still serve infected HTML for a week because Cloudflare was happily caching the old version.

wp cache flush handles the object cache. Whatever your page-cache plugin’s purge command is, run it. The Cloudflare dashboard has a “Purge Everything” button. Use it.

Verify

Before you drop maintenance mode, check a handful of real URLs and view source. Look for:

  • Unknown <script> tags in <head>
  • Meta refresh redirects at the top of the body
  • Iframes pointing at domains you don’t recognize

Also paste your homepage into Google Search Console’s URL Inspection tool. If Google still has the infected version cached, request re-indexing.

A cleanup service charges you $500 for two hours you already had.

Nova Heaven Incident Response

When to Pay Someone Instead

There are three scenarios where doing this yourself is the wrong call.

1. The site is actively hemorrhaging traffic. Every hour it’s down or serving malware costs real money. A cleanup service that can be on it in 30 minutes is worth $500 if you’re losing $1,000 a day.

2. You don’t know SFTP or SQL. If any command in this post looked alien, don’t guess your way through a live compromise. You’ll miss the backdoor and be re-infected in 48 hours.

3. The infection is wider than WordPress. If the attacker got into your hosting panel, not just WordPress, the scope is larger than a WP cleanup. A good shop will check your other databases, cron jobs, and mail queues. DIY guides don’t cover that surface.

Otherwise, the process is the same one I’ve run on dozens of sites over the years. Snapshot the site. Rotate every password and every key. Diff core against a known-good WordPress download. Reinstall plugins fresh. Check the database for rogue admins and injected options. Purge every cache layer before anyone gets back in. Two hours, and no invoice waiting in your email the next morning.


If you want the file-diff step done automatically, including fresh-core comparison, uploads scan, webshell detection, and database injection checks, Nova Scan does all of it in one run. The free version handles everything in this post. nova scan overview.

~ SephX, Nova Heaven. The cleanup isn’t hard once you know the order to do it in.

© Nova Heaven. All rights reserved.