Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild

WordPress Malware Removal: Clean It Properly or Do It Again Next Week

Sean

Platform Writer

Aug 13, 2026
9 min read

Cleaning infected files is the visible half of the job and the less important one. If you do not find how they got in, you will be doing this again in a week — often from a backdoor that was planted long before the symptom you noticed. The order that works: take the site offline, snapshot everything for evidence, replace core and plugins with known-good copies, hunt the database and the entry point, then rotate every credential.

WordPress Malware Removal: Clean It Properly or Do It Again Next Week

This is triage under pressure, so the sequence matters more than the individual commands. Skipping the evidence snapshot to move faster is the mistake that makes the second cleanup harder than the first.

Table of contents

Contain and preserve before you clean

The instinct is to start deleting. Resist it for ten minutes — you are about to destroy the evidence that tells you how they got in.

  1. Put the site into maintenance mode or take it offline, so it stops serving malware to visitors and to search engines.
  2. Snapshot the full filesystem and database as they are. This is evidence, not a backup to restore from.
  3. Copy the access and error logs somewhere safe before they rotate away. This is usually where the entry point is visible.
  4. Note the timestamps of the earliest modified files — that bounds the window you need to search in the logs.
tar czf /root/evidence-$(date +%F).tar.gz /var/www/html
wp db export /root/evidence-db-$(date +%F).sql
cp /var/log/nginx/access.log* /root/evidence-logs/

Do not restore from a backup yet either. If the backdoor predates the backup — and it often does by weeks — you will restore the compromise along with the clean-looking site and conclude the malware is unkillable.

Find what changed

The fastest signal is modification time, because attackers rarely bother to reset it.

# Files changed in the last week
find /var/www/html -type f -mtime -7 -ls | sort -k8

# PHP files in directories that should never contain them
find /var/www/html/wp-content/uploads -name '*.php'

# Suspicious function calls
grep -rEl --include='*.php' \
  '(eval\(|base64_decode\(|gzinflate\(|str_rot13\(|assert\(|preg_replace\(.*/e)' \
  /var/www/html

# Very long single-line files -- typical of obfuscated payloads
find /var/www/html -name '*.php' -exec awk 'length > 1000 {print FILENAME; nextfile}' {} \;

Any .php file in wp-content/uploads is malicious. There is no legitimate reason for one to exist there. That single check finds a large share of infections.

Then compare against known-good copies, which is far more reliable than reading code:

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

These compare every file against the official release hashes and report modifications and additions. Anything flagged in core is definitive — core files are never legitimately edited.

Replace rather than clean

Cleaning an infected file by hand means being confident you spotted every insertion. Replacing it means being confident about nothing at all, which is a better position.

# Reinstall core, overwriting all core files
wp core download --force --version=$(wp core version)

# Reinstall every plugin from the repository
wp plugin list --field=name | xargs -I{} wp plugin install {} --force

# Same for themes
wp theme list --field=name | xargs -I{} wp theme install {} --force

This replaces core, plugins, and themes wholesale while leaving wp-content/uploads and the database, which is where your actual content lives.

Three things need manual attention because they cannot be replaced from a repository:

  • Custom or premium themes and plugins with no public copy — compare against the vendor’s original download if you have one.
  • wp-config.php — check for injected code above or below the normal contents.
  • Files outside the WordPress directory.htaccess at any level, and anything the web server can execute.

Delete any plugin or theme you are not using rather than leaving it deactivated. A deactivated plugin’s files are still on disk and still reachable by URL, so a vulnerability in one is exploitable whether or not WordPress has it switched on.

The database and the persistence mechanisms

Cleaning files while leaving a database backdoor means the infection returns on the next page load.

-- Injected scripts in post content
SELECT ID, post_title FROM wp_posts
WHERE post_content REGEXP '<script|eval\\(|base64_decode';

-- Unexpected administrators
SELECT u.ID, u.user_login, u.user_email, u.user_registered
FROM wp_users u
JOIN wp_usermeta m ON m.user_id = u.ID
WHERE m.meta_key = 'wp_capabilities'
  AND m.meta_value LIKE '%administrator%';

-- Options that autoload on every request
SELECT option_name, LEFT(option_value, 200)
FROM wp_options
WHERE autoload = 'yes'
  AND option_value REGEXP 'eval\\(|base64_decode|<script';

That last query matters. Autoloaded options run on every page load, which makes them the ideal place to hide a reinfection routine — it survives file cleanup and rewrites the payload the moment you finish.

Also check scheduled tasks, another common persistence spot:

wp cron event list
crontab -l -u www-data
ls -la /etc/cron.d/

A cron entry that re-downloads a payload every hour is the reason “I cleaned it and it came back” is such a common experience.

Close the door

The part that determines whether you are finished. Search the logs for the first appearance of the earliest modified file — that request is usually the entry point.

grep -F 'suspicious-file.php' /var/log/nginx/access.log*

# POST requests to unusual paths
awk '$6 ~ /POST/' /var/log/nginx/access.log | grep -vE '(wp-login|admin-ajax|wp-cron)' | tail -50

# Successful admin logins and where from
grep 'wp-login.php' /var/log/nginx/access.log | awk '$9 == 302' | tail -50

The realistic causes, in rough order of frequency: an outdated plugin with a known exploit, a nulled or pirated theme that shipped with a backdoor, a weak or reused administrator password, stolen SFTP or hosting credentials, and a neighbouring site on the same shared account.

Then rotate everything, because you cannot know what was read:

  • All WordPress user passwords, especially administrators.
  • The database password, in the database and in wp-config.php.
  • SFTP, SSH, and hosting control panel credentials.
  • API keys and payment gateway credentials stored in plugin settings.
  • The salts and keys in wp-config.phpwp config shuffle-salts invalidates every existing session.

That last one logs out everyone, including the attacker, and it is the step people skip. A valid session cookie survives a password change; it does not survive a salt rotation.

Afterwards

  1. Request a review in Google Search Console if the site was flagged, and check the Security Issues report.
  2. Scan again with a second tool — different scanners catch different signatures.
  3. Set up automatic updates for plugins, or a routine that applies them within days rather than months.
  4. Take backups that are stored off the server, so an attacker with filesystem access cannot delete them.
  5. Add file integrity monitoring, so the next modification is noticed rather than discovered by a customer.
  6. Remove every plugin and theme you are not actively using.

Backups stored on the same server as the site are not backups. An attacker with write access deletes them along with everything else, and a disk failure takes both at once.

The structural improvement is deploying the site’s code from a repository instead of editing it in place, so unexpected file changes are visible as a difference rather than invisible until a scanner finds them — and so a rollback is available when something goes wrong. Alongside that, database backups you can restore from and a dashboard file manager and database browser mean the incident work does not depend on SSH access you may not have. That combination is what WordPress on RunxBuild provides, on plans starting at $3/month.

How this fits the rest of the stack

Contain first, snapshot for evidence, then replace core and plugins wholesale rather than cleaning files by hand. Check the database for autoloaded options and unexpected administrators, since that is how reinfection survives a file cleanup. Find the entry point in the access logs and rotate every credential, including the salts.

Any .php file under wp-content/uploads is malicious, and wp core verify-checksums is a free integrity check worth running regularly. If you are working out what hosting with off-server backups and a rollback path costs, the RunxBuild hosting calculator shows the plan, storage, and bandwidth separately.

Useful related references:

FAQ

How do I know if my WordPress site has malware?

Run wp core verify-checksums and wp plugin verify-checksums --all to compare files against official releases. Look for recently modified files with find -mtime -7, and check for any .php file under wp-content/uploads, which is never legitimate. Unexpected admin users and browser warnings are other strong signals.

Should I restore from a backup to remove malware?

Not as a first step. Backdoors often predate the backup by weeks, so restoring reinstates the compromise along with the clean-looking site. Identify how the attacker got in and when, then decide whether any backup is genuinely from before that point.

Why does WordPress malware keep coming back?

Because the persistence mechanism survived. The usual culprits are an autoloaded row in wp_options that rewrites the payload on every page load, a scheduled cron task that re-downloads it, an unnoticed admin account, or the original vulnerability still being open. Clean the database and close the entry point, not just the files.

What is the most common way WordPress sites get hacked?

An outdated plugin with a publicly known vulnerability. After that: nulled or pirated themes that ship with a backdoor, weak or reused administrator passwords, stolen SFTP credentials, and cross-contamination from another site on the same shared hosting account.

Do I need to change passwords after cleaning malware?

Yes, all of them — WordPress users, the database, SFTP and SSH, the hosting panel, and any API keys in plugin settings. Also rotate the salts in wp-config.php with wp config shuffle-salts, which invalidates existing sessions. A password change alone does not evict someone holding a valid session cookie.

#wordpress security#malware removal#hacked site#wordpress#security