A Calm WordPress Malware Cleanup Process

The moment you discover your site is hacked — a browser warning, a defaced page, spam links in your search results, or a hosting suspension email — your instincts will offer three bad ideas at once: delete suspicious-looking files immediately, restore last week’s backup and hope, or install five scanner plugins and let them fight it out. All three destroy evidence, and two of them leave the attacker’s door wide open.

Malware cleanup is not a battle of wits with a hacker. It is a procedure — the same six phases every time, in the same order. Almost every compromised WordPress site was hit by automation exploiting a known weakness, which means the cleanup is also fundamentally mechanical. Work the phases; skip none.

Phase 1: Contain (First Hour)

Before cleaning anything, stop the bleeding and stop the spreading:

  • Put the site into maintenance mode or password-protect it at the server level (an .htaccess basic-auth wall works). This protects your visitors from whatever the malware serves them and cuts off the attacker’s audience. Do not take the server fully offline yet — you need access to it.
  • Rotate the credentials that grant entry: hosting control panel, SFTP/SSH, and the database password (update wp-config.php to match). Do this from a computer you trust — if there is any chance your own machine is the source of the leak, use a different device.
  • Check for administrators you did not create. Users → Administrators. Attackers routinely add an innocuous-looking admin as a comeback route. Remove any you cannot vouch for.
  • If the site sends email, pause it. A common monetization of hacked sites is spam relay, and every spam batch dug your domain reputation deeper into a hole.

Phase 2: Preserve Before You Clean (Next 30 Minutes)

This is the phase everyone skips and later regrets. Take a full snapshot of the infected site — all files plus a database dump — and store it off the server, clearly labeled as infected. Two reasons:

  1. The infected copy is your forensic record. Timestamps on malicious files, log entries, and injected database rows are how you will later answer the only question that prevents reinfection: how did they get in?
  2. Cleanups occasionally go wrong. If you delete something load-bearing at 1 a.m., the infected-but-functional snapshot is your undo button.

Also download your server access and error logs right now — many hosts rotate them within days, and they are the closest thing to security camera footage you have.

Phase 3: Diagnose the Scope (An Honest Hour)

You cannot clean what you have not found, and WordPress malware hides in predictable places. Scan methodically:

Files

  • Compare core against the originals. WordPress core files have known checksums. With WP-CLI: wp core verify-checksums lists every modified or added core file in seconds. This alone often maps most of an infection.
  • Look for PHP where PHP does not belong: anything ending in .php inside wp-content/uploads/ is guilty until proven innocent. Same for files named to blend in — wp-config-sample-backup.php, class-wp-cache.php in odd directories.
  • Search for obfuscation signatures: eval(, base64_decode(, gzinflate(, str_rot13(, and very long single-line files. Legitimate plugins occasionally use these, so treat hits as leads, not verdicts.
  • Sort by modification time. Files changed in a cluster at some odd hour, when you deployed nothing, draw the timeline of the attack for you. (Attackers sometimes forge timestamps, but automation frequently does not bother.)

Database

  • Unfamiliar admin users (again — check the database directly this time, since malware can hide users from the admin UI).
  • Injected <script> tags or iframes in wp_posts content.
  • Rogue entries in wp_options — especially siteurl/home tampering and suspicious autoloaded blobs.

Scheduled tasks

Check WP-Cron events (wp cron event list) and the server’s crontab. A malicious cron job that re-downloads the malware every hour is the classic explanation for “I cleaned it and it came back the same day.”

Phase 4: Rebuild From Known-Good Sources (The Actual Cleanup)

Here is the philosophy that separates durable cleanups from recurring ones: do not clean infected files — replace them. Hand-editing malware out of files is error-prone, and obfuscated backdoors are specifically designed to survive a human skim. Fresh copies from official sources contain zero malware by construction.

  1. Replace all of core. Delete wp-admin/ and wp-includes/ entirely and extract fresh copies from wordpress.org for your exact version. Replace the root PHP files too, keeping only your wp-config.php (which you will now read line by line — attackers love appending an innocent-looking include at the bottom).
  2. Replace every plugin and theme from source. Delete each plugin directory and reinstall the same version from the official repository or the vendor. Anything abandoned, unlicensed, or — let us say it plainly — nulled does not get reinstalled. Nulled plugins are the single most self-inflicted infection vector in WordPress; the pirated copy of a paid plugin is the malware.
  3. Audit what cannot be replaced. Custom themes and one-off code must be reviewed manually or diffed against your version control. If you have no clean copy and no repository, this is the moment you learn why developers insist on git.
  4. Sweep uploads. Media directories should contain media. Delete every PHP, and check for HTML files with redirect payloads.
  5. Clean the database findings from Phase 3: remove rogue users, injected scripts, and malicious options. Take a dump before and after.

Phase 5: Rotate Everything, Then Verify

Assume every secret the site knew is compromised, because the attacker could read wp-config.php and the users table:

  • All WordPress user passwords (force reset for everyone), and invalidate sessions.
  • The salts and keys in wp-config.php — generate a new set; this logs out all cookies, including any the attacker holds.
  • Database password, SFTP/SSH keys and passwords, hosting panel — again if you rotated in Phase 1, since the attacker may have watched the first rotation.
  • API keys stored in the site: payment gateway keys, SMTP credentials, CDN tokens. This is the rotation people forget, and stolen SMTP credentials fund spam operations for months.

Then verify the cleanup: run the checksum verification again (should be silent), rescan with a reputable scanner, crawl the site as Googlebot (cloaked spam often shows only to crawlers — use Search Console’s URL inspection), and check the site against blocklists. If Google flagged you, request a review in Search Console once you are genuinely clean; reviews typically resolve within a few days.

Phase 6: Close the Door They Used

A cleanup without a root cause is a scheduled rerun. From your preserved logs and file timeline, determine the entry point. In practice it is nearly always one of:

Entry pointTelltale signsThe fix
Vulnerable plugin/themePOST requests to a specific plugin path right before first malicious file appearedUpdate or remove it; enable auto-updates for security releases
Stolen/weak credentialsSuccessful login from an unfamiliar IP, no exploit traffic2FA for all admins, password manager, rate limiting
Nulled softwareBackdoor present in the plugin’s own files from day oneBuy the license or use a free alternative. No exceptions.
Cross-site contaminationMultiple sites in one hosting account infected simultaneouslyIsolate sites into separate accounts/containers
Compromised host/serverInfection outside web root, host announcementsEscalate to the host; consider migrating

If the logs are gone and you truly cannot determine the cause, be honest about what that means: you must fix all plausible doors — update everything, add 2FA, isolate sites, and watch the file integrity monitoring closely for the next month.

What About Just Restoring a Backup?

A restore is legitimate if you can prove the backup predates the compromise — which your Phase 3 file timeline tells you — and if you still do Phases 5 and 6 afterwards. Restoring a pre-infection backup without rotating credentials or closing the entry point simply resets the clock on the same attack. Also verify the assumed-clean backup with the same scans; infections are routinely discovered weeks after they began, and last month’s backup may already contain the seed.

Reducing the Blast Radius of Next Time

Emerging from a cleanup is the one moment when security budget approves itself. Spend the goodwill on: automatic security updates, off-server daily backups with retention measured in months (not days), file integrity monitoring so the next incident is discovered in hours instead of weeks, 2FA everywhere, and deleting the plugins nobody remembers installing. The average time between infection and discovery is the number that determines how bad these incidents get — everything on that list shrinks it.

The Calm Summary

Contain. Preserve. Diagnose. Rebuild from known-good sources rather than scrubbing infected files. Rotate every secret the site ever held. Close the specific door, or all plausible doors. It is six phases, perhaps a full day of focused work, and none of it requires genius — only the discipline not to skip the unglamorous steps while adrenaline insists that you should.

Photo: Anete Lusina on Pexels