WebCare.

WordPress problem fix

MALWARE KEEPS REAPPEARING IN wp-content/mu-plugins/ AFTER YOU DELETE IT

Must-use plugins run on every request, load before regular plugins, and never show in the WordPress plugin list. That is exactly why attackers put their backdoor there.

4 hour emergency response You only pay when it is fixed 150+ WordPress sites managed
Reviewed by Ali Yasin Jatoi, Founder & Lead Engineer

The short answer

If you clean a WordPress site, redeploy from a known-good backup, and 24 hours later the malware is back, the persistence layer is almost always in wp-content/mu-plugins/. WordPress auto-loads every PHP file in that directory on every request, with no admin UI to disable them and no plugin activation hook required. Attackers use it as a stealth backdoor: 0wp-security.php, mu-loader.php, or a random eight-character filename that looks like core. The fix is to (1) inventory every file in mu-plugins against a known-good list, (2) hash-compare anything you do not recognize, (3) delete the malicious file, (4) lock the directory with correct ownership and a deny-PHP rule for uploads, then (5) run a daily file-integrity scan so any new file in mu-plugins triggers an alert before it earns a 24-hour head start.

Is this your situation?

If any of these match, you are on the right page.

The site is reinfected within hours or days of every cleanup, even after a fresh database and core reinstall

wp-content/mu-plugins/ contains files you did not put there (often named like 0wp-security.php, mu-loader.php, or 8-char random)

New admin users keep appearing even after you remove them and rotate passwords

Outbound network requests from your server to IPs in Russia, China, or known C2 infrastructure

The mu-plugins directory has changed permissions or ownership compared to wp-content/plugins/

What usually causes it

Why do attackers prefer mu-plugins over the regular plugins directory?

Regular plugins show in the dashboard plugin list. Site owners scan that list, see something unfamiliar, deactivate it. Must-use plugins never appear there — there is no activation, no deactivation, no visibility from the WP admin UI. A malicious mu-plugin can run on every request for months before anyone looks at the filesystem.

How did the attacker get write access to mu-plugins in the first place?

Usually one of: a vulnerable plugin with file-upload, a stolen FTP/SSH credential, a compromised hosting control panel, a server-level RCE in an outdated PHP version, or — most common in 2025 — a shared-hosting tenant compromise that gave the attacker write access to every site on the same hardware.

Why does deleting the mu-plugin file not stop the reinfection?

Because the mu-plugin is usually a stage-2 payload, not the entry point. The attacker also dropped a webshell elsewhere (often in /wp-content/uploads/ with a .php extension, or appended to a core file like wp-blog-header.php) that re-writes the mu-plugin every few hours from a remote source. You have to kill all the persistence layers in the same maintenance window.

Why is WordPress not catching this?

WordPress core has no integrity check for mu-plugins by design — that directory exists precisely to let hosts and agencies inject code that core should not touch. Security plugins like Wordfence catch known signatures but miss bespoke malware with zero detections.

How we fix it

The real method, in the order it works.

  1. 1

    Inventory wp-content/mu-plugins/ against your known-good list. If you do not have one, the safe baseline for most sites is empty (no files) or one or two host-injected loaders (e.g. WP Engine's mu-plugin loader). Anything else is suspect.

  2. 2

    Hash every suspect file with sha256sum and search the hash on VirusTotal and the Patchstack vulnerability DB. A clean hash with zero detections does not mean clean — bespoke malware is unsigned by definition.

  3. 3

    Read the file. Look for base64_decode, eval, gzinflate, str_rot13, assert with variable arguments, file_get_contents on a remote URL, or admin user creation (wp_insert_user with administrator role). Any of those in a file you did not write is malicious.

  4. 4

    Before deleting: snapshot the file to a quarantine folder outside the webroot, save the timestamp, save the file owner, save inbound HTTP logs for the last 7 days. You will need this for the post-incident audit.

  5. 5

    Delete the file. Run a full malware scan across wp-content/, wp-includes/, and wp-admin/. Look for files modified within 60 minutes of the malicious mu-plugin's last-modified timestamp — that is the dropper.

  6. 6

    Harden: chmod mu-plugins to 0755, set ownership to the web user (not root), add a .htaccess deny-PHP rule to wp-content/uploads/, rotate all admin passwords, rotate all FTP/SSH/SFTP credentials, rotate the hosting control panel password, force-logout all sessions.

  7. 7

    Install a daily file-integrity monitor (we use a homegrown one but Wordfence, Sucuri, or Patchstack work). Configure it to alert on any new file in mu-plugins, wp-content/uploads/*.php, or wp-includes/*.php — those three patterns catch 90% of WordPress backdoors.

Real fix, from our work

How this one actually went down

We ran into this on a UK agency network we maintain. Three sites had been cleaned by another freelancer the week before — fresh core, fresh database, all passwords rotated — and within 72 hours all three were reinfected. The agency thought they had a hosting-level breach. They did not. They had three different mu-plugins (one called 0wp-security.php, two with 8-character random names) that the cleanup had not touched because mu-plugins does not show in the WP admin. The reinfection vector was a webshell in /wp-content/uploads/2023/04/.cache.php that re-wrote the mu-plugin every 6 hours from a remote payload. We deleted the mu-plugins, deleted the webshell, locked /uploads/ to deny PHP, and rotated every credential the agency owned. Zero reinfections in the 8 months since.

AJ

Written by Ali Yasin Jatoi

Founder of WebCare Studios. Ali has worked with WordPress for more than 10 years, including managing a fleet of 150+ sites with WP-CLI automation for updates, security cleanup, and malware removal. He has hands on experience across major hosts including Cloudways, A2 Hosting, Hostinger, and Bluehost.

Why owners pick WebCare

4 hour emergency response

Site down, hacked, or broken checkout gets a senior engineer within 4 hours. No ticket queues, no bots.

You only pay when it is fixed

Flat quote up front. If we cannot get you back online, you do not pay. Risk sits with us, not you.

Data safe approach

We work on a snapshot first and never touch your live database until the fix is verified safe.

150+ sites managed

We run a fleet of WordPress sites every day. The errors you are seeing are ones we have closed hundreds of times.

Common questions

Is every file in mu-plugins malicious?+

No. Hosts (WP Engine, Kinsta, Pantheon, Pressable) legitimately inject mu-plugins to handle caching, object cache wiring, or platform integration. Agencies legitimately use mu-plugins for must-load functionality that should not be deactivatable. The question is whether you can account for every file. If you cannot, treat the unknown ones as suspect.

Can I just delete the whole mu-plugins directory?+

On a managed host: no — you will break caching or platform integration and your site may go offline. On a self-hosted site: usually yes, as long as you confirm no legitimate functionality lives there. Take a backup first.

Will Wordfence or Sucuri catch this?+

Sometimes. Both have decent signature databases for common mu-plugin malware (0wp-security family, mu-loader family, the WSO webshell). They miss bespoke or freshly-modified payloads. We pair signature scanning with file-integrity monitoring for exactly this reason — the integrity monitor catches what the scanner does not.

Why does the attacker rewrite the mu-plugin every few hours instead of just leaving it?+

Two reasons. (1) If a sysadmin notices and deletes it, the dropper puts it back before the next request. (2) Some hosts run nightly malware scans — a fresh payload each day is more likely to evade signature detection than one that has been on disk for 30 days.

Do I need to reinstall WordPress core after a mu-plugin compromise?+

Yes. If the attacker had write access to mu-plugins, they almost certainly had write access to wp-includes/ and wp-admin/ too. Reinstall core from a fresh download (wp-cli core download --force) and hash-compare every file under wp-includes/ and wp-admin/ against the canonical hashes.

Send my site for triage in 15 minutes

Two fields. Email and your URL. A senior WordPress engineer reads it within minutes and replies on email and WhatsApp with what is wrong and what we will do next.

Two fields. Senior engineer replies within 15 minutes during business hours.

WhatsApp Get my site fixed

Proof and field guides

Real proof and field guides tied to "mu-plugin malware that keeps coming back".