A single hidden file on one WordPress site can quietly take over an entire server, and the trigger is a command your team might run without thinking. Running WP-CLI as root with --allow-root isn’t standard practice, but as recent telemetry shows, it does still happen in real hosting setups: cron jobs, control-panel automation, deployment scripts. It exists to avoid the friction of dropping to each site’s own system user. It is also the door an attacker walks through. Wherever that pattern is in place, it is tempting to treat a read-only command such as wp plugin list or wp user list as harmless. It is not. Any command that boots WordPress unconditionally executes every must-use plugin (wp-content/mu-plugins/*.php) at load time, before a single line of the command’s own logic runs. So if an attacker drops a malicious .php file into one account’s mu-plugins/, the next time an operator runs any WordPress-loading command as root with --allow-root (even just a harmless wp plugin list), the full payload is loaded. We have seen the same pattern across different hosting environments running similar automation, where everyday WordPress maintenance workflows can quietly become a privilege-escalation path.

This is not theoretical

We are not describing a lab curiosity. Imunify360 telemetry has observed this exact exposure in the wild (must-use-plugin droppers sitting on servers whose operators run WP-CLI as root) across multiple hosting environments. The CloudLinux research team is engaging the affected providers directly with remediation guidance and safer operational practices, which is a large part of why we are publishing this. The pattern is common enough, and quiet enough, to be worth a public warning.

How one compromised WordPress site silently takes over the whole server — Imunify (scope-backup-bit)

The setup operators actually use

Control panels and maintenance scripts frequently loop over every site on a server as root:

Bash loop running wp plugin list with --allow-root as root across every site

The intent looks read-only and safe. The reality is that each iteration fully bootstraps that customer’s WordPress, and runs their mu-plugins code as root.

And it is far from just plugin's list. In our telemetry we see a broad spread of these root invocations across real hosts for status checks, cache and object-cache maintenance, config reads, content and user listings:

Everyday WP-CLI commands run as root with --allow-root from automation

Why “read-only” is a myth here

WordPress loads must-use plugins on every boot unconditionally. They have no activation switch and no hook; WordPress simply includes them. From wp-settings.php:

WordPress wp-settings.php loop that include_once's every mu-plugin, running its top-level code immediately

No capability check, no is_admin() gate, no hook. Any top-level statement runs the instant WordPress starts, a web request, cron, or CLI alike.

👇 Take these as examples the following inoffensive commands an operator fires off without a second thought:

CommandCategoryMU-plugin runs?
wp plugin listRead-only listing💥 Yes
wp user listRead-only listing💥 Yes
wp post listRead-only listing💥 Yes
wp option getRead-only listing💥 Yes
wp option updateWrite💥 Yes
wp cache flushMaintenance💥 Yes
wp rewrite flushMaintenance💥 Yes
wp cron event runMaintenance💥 Yes
wp search-replaceMaintenance💥 Yes
wp plugin update --allMaintenance💥 Yes
…and many othersAnything that boots WordPress💥 Yes

Note: --skip-plugins do NOT skip must-use plugins.

This is expected, documented behaviour, still present as of the latest WP-CLI release (v2.12.0) — see WP-CLI PR #2480.

Patient zero: how the first Malware crafted MU-plugin lands

The whole chain starts at the level of a single account, never root, no LPE, the attacker only needs to write one PHP file into one site’s mu-plugins/. The usual ways in are ordinary:

  • A compromised admin account: phished, brute-forced, or reused credentials.
  • A hijacked session: a stolen wordpress_logged_in cookie is enough; no password required.
  • An abused file-manager plugin: With WP File Manager installed, the built-in file browser is all it takes: so a plain admin, using nothing but the WP File Manager GUI’s documented file operations (New Folder -> mu-plugins/ , New File -> the payload), plants an auto-executing MU-plugin. (Older versions also allowed unauthenticated attackers to upload arbitrary files – CVE-2020-25213).
  • A rogue admin written straight to the database: More sophisticated malware inserts its own hidden administrator row for durable persistence, then uses that account to drop the MU-plugin.

Malware in the wild: the scope-backup-bit family

Imunify360 telemetry caught a recent campaign with this exact mechanism being used as a distribution channel by a self-spreading, obfuscated mu-plugin family. On a single monitored server it found thousands of must-use-plugin files spread across dozens of tenant accounts.

Indicators of compromise

Family:      scope-backup-bit  (obfuscated mu-plugin backdoor)
SHA-256:     724e2ee968b0a19de5f6f90350c644cce0d4e889aa641d59ce1a931fe908ef3b
Aliases:     scope-backup-bit.php, elementor-safe-mode.php,
             async-environment-manager.php, grid-shield-tag/…,
             pulse-compiler-hq.php  (+ fresh, rotating aliases)

Analyzed:    "Scope Extension Jet" v4.5.8  (same family)
SHA-256:     8af2df58d53ef4973b3a1d8e3cff029a618f85eadd1a0a3c35be7170891fcb50

Detection:   SMW-SA-2038640-php.bkdr.obf-2
Artifacts:   owner=0 files in wp-content/mu-plugins/; root-owned mu-plugins/
             directory.


Why this matters for hosts specifically

  • One tenant compromises all tenants. The malware only needs write access to one account’s mu-plugins/ . Your root automation does the privilege escalation for the attacker, on schedule silently.
  • It’s silent. mu-plugins don’t appear in the standard Plugins list and aren’t disabled by --skip-plugins . Operators rarely look there.

Defense in depth with Imunify360

The primary recommendation stands on its own: disable --allow-root wherever possible in automation and control panels, and run WP-CLI under each site’s own user. Imunify360 provides multiple layers of protection that help stop this type of attack at different stages.

  • RASP layer catches the malware at runtime and block it.
  • Web Application Firewall (WAF) blocks the web-facing vectors droppers use to land in mu-plugins/ in the first place.
  • Imunify Security (WordPress plugin) complements the WAF from inside WordPress, adding enhanced coverage for known plugin and theme CVEs.
  • Malware scanning with heuristic detection flags obfuscated families like scope-backup-bit even as they rotate filenames (this campaign is detected as SMW-SA-2038640-php.bkdr.obf-2).

🔒 Imunify360 integrates natively with the CloudLinux ecosystem with CloudLinux OS, CageFS mitigation.