Published June 15, 2026, by the Patchstack Team
A supply chain attack against three popular WordPress marketing plugins (OptinMonster, TrustPulse, and PushEngage) served tampered JavaScript from their vendors’ CDNs to live websites. The injected code did not exploit a plugin vulnerability in the traditional sense. Instead, it ran inside the browser of any logged-in administrator who loaded an affected page, and used that administrator’s own session to silently create hidden admin accounts and install a self-hiding backdoor plugin.
Because the payload runs client-side with valid credentials and a valid nonce, every malicious request looks, at the network layer, almost exactly like a real administrator adding a user. That is what makes this campaign interesting, and what made it tricky to stop without breaking legitimate functionality.
Patchstack deployed a mitigation rule for this campaign, and over roughly 36 hours it blocked 271 exploitation attempts across customer sites. We will walk through how the attack works, what our firewall logs revealed, and exactly what you should do if you ran any of these plugins.
This research builds on the public disclosures from OptinMonster and Sansec, combined with our own analysis of a captured payload and our firewall logs.
About the vendor
OptinMonster, TrustPulse, and PushEngage are conversion and engagement tools published under the Awesome Motive umbrella, collectively installed on a very large number of WordPress sites.
According to Sansec, over 1.2 million sites were potentially exposed during this incident. These plugins load a small JavaScript SDK from a vendor-controlled CDN on the front end. This is the standard pattern for this category of product, and it is the exact mechanism the attacker abused.
What happened
Per OptinMonster’s disclosure, an attacker exploited a vulnerability in a third-party plugin (UpdraftPlus) running on OptinMonster’s marketing website to gain access to that server. From there they retrieved a CDN API key and used it to modify the JavaScript files served to customers from the CDN edge.
The tampered files were the plugins’ front-end SDKs:
a.omappapi.com/app/js/api.min.js(OptinMonster)a.opmnstr.com/app/js/api.min.js(OptinMonster)a.optnmstr.com/app/js/api.min.js(OptinMonster)a.trstplse.com/app/js/api.min.js(TrustPulse)clientcdn.pushengage.com/sdks/pushengage-web-sdk.js(PushEngage)
The malicious code was appended to the legitimate, minified SDK, so the file kept working normally while the attacker’s logic ran alongside it. No update was pushed to the plugins themselves. The change happened entirely at the CDN, which is why a fully up-to-date site could still be served the malicious script.
Timeline
- April 28, 2026: The command-and-control domain
tidio.ccis registered and issued a TLS certificate, indicating the campaign was prepared well in advance. - June 12, 22:17 UTC: Malware first observed in the OptinMonster and TrustPulse
api.min.jsfiles. - June 12, 22:42 UTC: Last verified presence of the malware on the OptinMonster and TrustPulse CDNs.
- June 13, 19:02 UTC: The PushEngage SDK is still serving injected code from certain CDN edges.
- June 14, 2026: PushEngage malware removed; OptinMonster publishes its incident disclosure.
- June 14–15, 2026: Patchstack’s mitigation rule actively blocks auto-exploitation attempts across protected sites.
The exposure window for OptinMonster and TrustPulse was short, but the tampered PushEngage SDK lingered on some CDN edges into June 13–14 as caches were purged.
How the attack works
We analyzed a captured copy of the injected payload. It is a self-contained script bolted onto the end of the genuine SDK, and it executes a careful, staged routine designed to run only where it will succeed and stay quiet everywhere else.
1. Environment and victim checks. Before doing anything, the script tries to avoid researchers and automated tooling. It checks for navigator.webdriver, headless markers like window._phantom and window.__nightmare, and zero-size browser windows. It then confirms it is running in a genuine WordPress admin context by looking for the admin bar, /wp-admin/ paths, and the wordpress_logged_in_ cookie. If it is not in front of a logged-in administrator, it simply stops. It also stamps localStorage so it will not re-run on the same browser for 24 hours.
2. Locating the site and harvesting a nonce. It determines the WordPress root and admin path, fingerprints the WordPress version from the generator tag and asset query strings, and then harvests a valid REST nonce from inline wpApiSettings, from admin-ajax.php?action=rest-nonce, or by scraping the new-user page. With a valid nonce plus the admin’s own cookies, the script can make authenticated requests as the administrator.
3. Creating a rogue administrator in four ways. This is the core of the attack. The payload tries multiple methods in sequence until one succeeds:
- REST API:
POST /wp-json/wp/v2/users(and the?rest_route=/wp/v2/usersform) with a JSON body requesting theadministratorrole. - Admin form:
POST /wp-admin/user-new.phpwithaction=createuser. - AJAX:
POST /wp-admin/admin-ajax.phpwith the samecreateuserpayload. - Hidden iframe: a 1×1 invisible iframe that loads
user-new.php, fills the form, and submits it.
It plants both a fixed account and randomized accounts:
// Fixed identity baked into one observed sample
USER: "developer_api1",
EMAIL: "customer1usx@gmail.com",
// Randomized variant seen overwhelmingly in the wild
// dev_xxxxxx / dev_xxxxxx@gmail.com (administrator role)
The script even carries a multi-language dictionary of “user already exists” messages so it can tell, across localized WordPress installs, whether the account was created or already present.
4. Installing a self-hiding backdoor. Once it has admin access, the payload fetches a generated ZIP from its C2 and uploads it via POST /wp-admin/update.php?action=upload-plugin. The backdoor masquerades under rotating random names such as “Content Delivery Helper” (content-delivery-helper) or “Database Optimizer” (database-optimizer), and actively conceals itself from the plugin list, user list, updates screen, and activity logs.
Per Sansec, it exposes a web shell (“WPM File Manager & Shell”) via the ?developer_api1_fm parameter that runs system($_POST['cmd']), plus a developer_api1_eval endpoint that executes base64-decoded attacker input.
5. Exfiltration. Results are XOR-encrypted with the key jX9kM2nP4qR6sT8v, base64-encoded, and beaconed to tidio.cc/cdn-cgi/pe-* using a resilient chain of navigator.sendBeacon, fetch, XMLHttpRequest, and finally an image-pixel fallback.
The key takeaway: this is not a CSRF or a plugin bug. The malicious requests carry the administrator’s legitimate session and a legitimate nonce, because the administrator’s own browser is the one making them. The administrator is the victim, not the attacker.
What our firewall logs show
Because the requests are authenticated and well-formed, the only reliable signal at the HTTP layer is the attacker’s own indicators: the specific account identities and the backdoor’s parameter names. We built the mitigation rule around those values, and the telemetry confirms it caught the campaign cleanly.
Between June 14 and June 15, 2026, the rule blocked 271 requests across 13 distinct sites originating from 81 unique IP addresses:
| Endpoint | Blocked requests | Vector |
|---|---|---|
/wp-json/wp/v2/users | 263 | REST API account creation |
/wp-admin/user-new.php | 5 | Admin form / iframe |
/wp-admin/admin-ajax.php | 3 | AJAX account creation |
| Total | 271 |
Every blocked request was a rogue-admin creation attempt matching this campaign. 267 used the randomized dev_xxxxxx / dev_xxxxxx@gmail.com identities and 4 used the fixed developer_api1 / customer1usx@gmail.com account. The version distributed at scale clearly favored randomized names, while the fixed identity appeared mainly through the form-based path.
A representative blocked REST request:
POST /wp-json/wp/v2/users
{
"username": "dev_3m6nyp",
"email": "dev_wvi65g@gmail.com",
"password": "lSwI4oUwH%&uCZ@7NW2*",
"roles": ["administrator"]
}
Two details stand out in the data:
- The traffic is residential, not centralized. The blocked requests came from 81 different IPs and a wide mix of consumer browsers: roughly 60% mobile (Android/Samsung), with the rest Windows, macOS, and desktop Linux, including a couple of Googlebot user agents. This is exactly what you would expect when the malicious code executes inside the browsers of real site administrators rather than from a single attacker server.
- Sites were hit in rapid bursts. Individual sites show clusters of account-creation attempts seconds apart, as the script worked through its fallback chain and sprayed multiple randomized administrators in one visit. Two sites alone accounted for nearly 200 of the blocked attempts.
Patchstack’s mitigation
A web application firewall cannot stop a browser from loading a compromised CDN script, and it cannot see the encrypted beacon to tidio.cc (that traffic goes to a third-party origin). What it can do is block the on-site actions the payload performs, by matching the attacker’s hardcoded indicators precisely enough to avoid touching legitimate admin work.
Our rule blocks:
- Rogue administrator creation and login: any request that creates or authenticates the fixed
developer_api1/customer1usx@gmail.comidentity, or the randomizeddev_xxxxxx/dev_xxxxxx@gmail.compattern, across the REST, form, and AJAX vectors. - Backdoor web shell access: any request carrying the
developer_api1_fmordeveloper_api1_evalparameters used by the planted plugin.
Because the rule keys on attacker-specific values rather than on the act of creating a user, the false-positive risk for sites running these plugins is effectively zero. No legitimate administrator creates a user named developer_api1 with the email customer1usx@gmail.com, or logs in as one.
This is a mitigation, not a cleanup. It stops the auto-exploitation from succeeding on a still-exposed site, but it does not remove a rogue admin or backdoor that was created before protection was in place.
Indicators of Compromise (IOC)
Rogue accounts
developer_api1/customer1usx@gmail.comdev_xxxxxx/dev_xxxxxx@gmail.com(randomized, six characters)
Backdoor plugins (rotating disguises)
content-delivery-helper: “Content Delivery Helper” (v2.7.1)database-optimizer: “Database Optimizer” (v2.9.4)- UI string: “WPM File Manager & Shell”
Backdoor parameters
?developer_api1_fm(web shell),developer_api1_eval(code execution)
Command and control
- Domain:
tidio.cc(IP84.201.6.54, Ultahost AS214036) - Paths:
/cdn-cgi/p,/cdn-cgi/b,/cdn-cgi/l,/cdn-cgi/pe-p,/cdn-cgi/pe-b,/cdn-cgi/pe-l
Malware signature
- XOR key:
jX9kM2nP4qR6sT8v
Tampered CDN files
a.omappapi.com/app/js/api.min.js,a.opmnstr.com/app/js/api.min.js,a.optnmstr.com/app/js/api.min.js,a.trstplse.com/app/js/api.min.js,clientcdn.pushengage.com/sdks/pushengage-web-sdk.js
What you should do
If you ran OptinMonster, TrustPulse, or PushEngage and an administrator visited the site during the exposure window (around June 12–14, 2026), treat the site as potentially compromised and check it manually. Remediating the vendors’ systems does not clean a site that was already attacked.
- Audit administrator accounts. Delete
developer_api1and anydev_xxxxxxaccounts. Review all admin users for anything you do not recognize. - Check the filesystem, not just the dashboard. The backdoor hides from the admin UI. Inspect
wp-content/plugins/directly forcontent-delivery-helper,database-optimizer, or any unfamiliar plugin, and grep your codebase fordeveloper_api1_fm,developer_api1_eval, and the XOR keyjX9kM2nP4qR6sT8v. - Run a server-side malware scan for comprehensive detection beyond the known names.
- Rotate everything if you find a compromise: administrator passwords, API keys, database credentials, and the WordPress security keys/salts in
wp-config.php. - Block the C2
tidio.cc(84.201.6.54) at the DNS or network layer.
Conclusion
This incident is a clear reminder that the software supply chain extends past the plugins you install to every third-party asset they load at runtime. A site that was fully patched and well configured could still be served malicious code, because the compromise happened on a vendor’s CDN, not on the customer’s site. And because the payload weaponized the administrator’s own authenticated session, the resulting requests were nearly indistinguishable from legitimate activity.
The defensible signal in cases like this is the attacker’s own fingerprints. By keying on the specific rogue identities and backdoor parameters, Patchstack’s rule blocked 271 real exploitation attempts in its first day and a half without disrupting legitimate site management. If you depend on third-party scripts, and almost every WordPress site does, assume that “trusted” assets can turn hostile, and make sure something is watching the requests they generate.