Awesome Motive CDN Supply-Chain Attack — OptinMonster / TrustPulse / PushEngage Tampered CDN Scripts
Executive Summary
Attackers compromised an Awesome Motive CDN API key and used it to inject malicious JavaScript into plugin files served from the official CDNs behind three widely deployed WordPress plugins: OptinMonster, TrustPulse, and PushEngage. Because the payload was delivered through the vendors' trusted CDNs rather than the plugin install on disk, sites pulled tampered code without any local file change — a classic browser-side supply-chain compromise affecting an estimated ~1.2 million sites (OptinMonster alone is installed on roughly 1.2M sites).
The tampered CDN JavaScript executes in the browser of any logged-in WordPress administrator who loads an affected admin page. Riding that admin's authenticated session, it performs two actions silently: (a) creates a hidden rogue administrator account — the observed account is developer_api1 (email customer1usx@gmail.com), with additional dev_xxxxxx variants — and (b) installs a self-hiding backdoor plugin on disk under wp-content/plugins/, named content-delivery-helper ("Content Delivery Helper") and/or database-optimizer ("Database Optimizer"). The newly minted credentials are exfiltrated to tidio.cc, a typosquat lookalike of the legitimate tidio.com chat vendor; the C2 domain was registered 2026-04-28, two weeks before the campaign went live.
Source Review & Web Hunter Notes
| Tier | Source | Key Finding | Carry |
|---|---|---|---|
| 1 · Vendor research | Patchstack — Supply-chain attack on OptinMonster/TrustPulse/PushEngage | Tampered CDN scripts auto-creating rogue admins; IOC account / backdoor plugin names; tidio.cc exfil | yes |
| 1 · Vendor research | Sansec — OptinMonster supply-chain attack | Compromised CDN API key; injected JS abusing admin session; ~1.2M sites exposed; timeline | yes |
| 1 · News of record | BleepingComputer — OptinMonster plugin hacked in CDN supply-chain attack | Mechanism, affected vendors, PushEngage nodes serving payload through 2026-06-14 | yes |
| 2 · News | Security Affairs — Supply-chain attack hits popular WordPress plugins via Awesome Motive CDN | Corroboration of scope, root cause (CDN key), rogue-admin + backdoor behavior | partial |
Decisions: lead with the durable atomic IOC — the C2 domain tidio.cc — because it is concrete, low-FP, and pivots both network and DNS telemetry. Pair it with the on-disk artifacts (backdoor plugin directory names) and the identity artifact (rogue admin account names). The CDN injection itself is off-sensor; the remediation is to update the plugins to the cleaned versions, purge the CDN cache, and audit every WordPress admin roster and wp-content/plugins/ directory for the planted artifacts. Treat the tidio* typosquat family as a small allow-list problem: tidio.com (and its legitimate subdomains/CDN) are benign; everything else tidio* is suspect.
Hunt Brief & Attack Chain
Working hypothesis: An organization runs one or more of OptinMonster / TrustPulse / PushEngage on a self-hosted WordPress site. Between 2026-06-12 and 2026-06-14 an administrator logged into wp-admin and loaded a page that pulled tampered JavaScript from the affected vendor CDN. The script used the admin's session to create a hidden developer_api1 / dev_* account and drop a self-hiding backdoor plugin (content-delivery-helper / database-optimizer) on disk, then exfiltrated the new credentials to tidio.cc for later hands-on-keyboard re-entry.
| Step | Behavior | Telemetry | Hunt Angle |
|---|---|---|---|
| 1 · Supply-chain inject | Compromised CDN API key injects malicious JS into plugin files on the vendor CDN (T1195.002) | Off-sensor (vendor CDN) | Native N1/N3; vendor advisory |
| 2 · Browser execution | Tampered CDN JS runs in the logged-in admin's browser (T1059.007) | Admin workstation web/proxy logs; DnsRequest | Q5; Native N2 |
| 3 · Create rogue admin | Hidden developer_api1 / dev_* admin account created via the admin's session (T1136) | WP audit log / DB; web-server process activity | Q3; Native N4 |
| 4 · Drop backdoor plugin | Web-server worker writes new plugin files under wp-content/plugins/ (T1505.003) | FileCreateInfo, ProcessRollup2 | Q4 |
| 5 · Exfil credentials | New admin creds POSTed to tidio.cc (T1567 / T1071.001) | DnsRequest, NetworkConnectIP4 | Q1, Q2 |
| 6 · Hands-on re-entry | Backdoor plugin / rogue admin used for follow-on web-shell behavior (T1505.003) | ProcessRollup2 (worker spawns shell) | Q6; Containment §11 |
Affected surface & telemetry
| Surface | Required Telemetry | Priority | Gap Risk |
|---|---|---|---|
| Web servers running affected WP plugins | DnsRequest, NetworkConnectIP4, FileCreateInfo, ProcessRollup2 | Critical | Low — standard Falcon sensor on the host |
| WordPress admin workstations | DnsRequest / proxy logs for browser-side CDN + C2 calls | High | Medium — depends on sensor / proxy coverage of admins |
| WordPress identity (admin roster) | WP audit-log plugin or DB wp_users / wp_usermeta review | High | High — off-sensor; needs WP audit logging or DB query |
| Vendor CDN integrity | Plugin version + CDN cache state (vendor-side) | Medium | High — off-sensor; relies on vendor remediation |
Consolidated IOC Table
| Type | Value | Conf | Action | Context |
|---|---|---|---|---|
| Domain (C2/exfil) | tidio.cc | high | block | Typosquat of tidio.com; reg. 2026-04-28; exfil of stolen admin creds |
| Domain pattern | tidio* (any TLD != tidio.com) | medium | hunt | Lookalike family; allow-list legitimate tidio.com only |
| Account | developer_api1 (customer1usx@gmail.com) | high | detect | Observed rogue WordPress admin account |
| Account pattern | dev_xxxxxx (unexpected admin role) | medium | hunt | Variant naming for auto-created rogue admins |
| File / dir | wp-content/plugins/content-delivery-helper | high | detect | Self-hiding backdoor plugin ("Content Delivery Helper") |
| File / dir | wp-content/plugins/database-optimizer | high | detect | Self-hiding backdoor plugin ("Database Optimizer") |
| Affected plugins | OptinMonster · TrustPulse · PushEngage | high | audit | Update to cleaned versions; purge CDN cache |
| Window | CDN script review 2026-06-12 → 2026-06-14 | high | hunt | Payload-serving window (PushEngage nodes latest) |
ATT&CK Mapping
| Tactic | Technique | Observed Behavior | Query / Control |
|---|---|---|---|
| Initial Access | T1195.002 — Compromise Software Supply Chain | Malicious JS injected into plugin files on the vendor CDN via stolen API key | N1/N3; S10 update |
| Execution | T1059.007 — JavaScript | Tampered CDN script executes in the admin's browser session | Q5; N2 |
| Persistence | T1136 — Create Account | Hidden developer_api1 / dev_* admin account auto-created | Q3; N4 |
| Persistence | T1505.003 — Server Software Component: Web Shell | Self-hiding backdoor plugin dropped under wp-content/plugins/ | Q4, Q6 |
| Command & Control | T1071.001 — Application Layer Protocol: Web | Backdoor / exfil beacons to tidio.cc over HTTP(S) | Q1, Q2 |
| Exfiltration | T1567 — Exfiltration Over Web Service | Stolen admin credentials POSTed to tidio.cc | Q1, Q2; §11 |
Native Audit-Log Hunts
| Hunt | Source | Logic | Response |
|---|---|---|---|
| N1 · Plugin inventory & version | WP admin / wp-cli | Identify sites running OptinMonster / TrustPulse / PushEngage and confirm they are on the cleaned post-incident versions | Update plugins; purge the CDN cache |
| N2 · CDN script-load review | Browser/proxy logs for admins; web-server access logs | Admin sessions that loaded affected-vendor CDN JS 2026-06-12 → 2026-06-14 | Treat any such admin session as potentially compromised; pivot to N4 |
| N3 · Backdoor plugin on disk | Filesystem audit of wp-content/plugins/ | Presence of content-delivery-helper or database-optimizer directories (often self-hidden from the admin plugin list) | Remove; treat host as compromised; pivot to Q4/Q6 |
| N4 · Rogue admin roster review | WP DB (wp_users/wp_usermeta) or audit-log plugin | Admin accounts named developer_api1 / dev_*, unexpected admins, or admins with email customer1usx@gmail.com | Delete rogue admins; rotate all admin creds; force re-login |
CrowdStrike LogScale CQL Hunt Queries
DnsRequest / proxy data — coverage depends on whether your admins' workstations are sensored. The C2 domain hunts (Q1/Q2) carry the highest fidelity: tidio.cc has essentially no benign baseline.Looks for: any DNS request for tidio.cc or a tidio* lookalike that is not the legitimate tidio.com. Accomplishes: the single highest-fidelity signal in the pack — near-zero benign baseline.
// HUNT: DNS lookups for tidio.cc C2 / non-tidio.com typosquat family // MITRE: T1071.001, T1567 | CONF: high FP: low COST: low // REQUIRES: DnsRequest telemetry from web servers and admin workstations // FALSE POSITIVES: legitimate tidio.com chat widget (explicitly excluded below) // TUNING: keep tidio.com (and its real CDN subdomains) on the allow-list; alert on all other tidio* #event_simpleName=/DnsRequest/i | DomainName=/(^|\.)tidio/i | DomainName!=/(^|\.)tidio\.com$/i | table([@timestamp, aid, ComputerName, DomainName, RequestType], limit=200) | sort(@timestamp, order=desc)
Looks for: outbound connections on web ports made by a PHP / web-server worker process — abnormal for a web server, and the path the backdoor uses to beacon/exfil. Accomplishes: catches the exfil even if DNS is cached or hard-coded to an IP.
// HUNT: Web-server worker process making outbound web connections (backdoor beacon / exfil) // MITRE: T1071.001, T1567 | CONF: high FP: low COST: medium // REQUIRES: NetworkConnectIP4 with initiating-process context // FALSE POSITIVES: legitimate plugin update/license checks, REST calls to known APIs // TUNING: allow-list sanctioned outbound endpoints (plugin update servers, payment gateways) #event_simpleName=/NetworkConnectIP4/i | ContextBaseFileName=/^(php|php-fpm[0-9.]*|httpd|apache2|nginx|w3wp)(\.exe)?$/i | in(RemotePort, values=[80, 443, 8080, 8443]) | RemoteAddressIP4!=/^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.|127\.)/ | table([@timestamp, aid, ComputerName, ContextBaseFileName, RemoteAddressIP4, RemotePort], limit=200) | sort(@timestamp, order=desc)
Looks for: the rogue-admin identifiers (developer_api1, customer1usx@gmail.com, dev_*) appearing in process command lines — e.g. a wp-cli user create, a DB client, or a script touching the account. FP: legitimate dev-named accounts — review hits. Pair with Native N4 (the authoritative roster check is in the WP DB).
// HUNT: Rogue WP admin identifiers (developer_api1 / customer1usx / dev_*) in process args // MITRE: T1136 | CONF: medium FP: medium COST: low // REQUIRES: ProcessRollup2 command-line telemetry on web servers // FALSE POSITIVES: legitimate developer accounts using a dev_ naming convention // TUNING: confirm against the WP DB (N4); allow-list known-good dev_ accounts #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/i | CommandLine=/(developer_api1|customer1usx@gmail\.com|user\s+create\s+dev_[a-z0-9]+|INSERT.+wp_users)/i | table([@timestamp, ComputerName, UserName, FileName, CommandLine, ParentBaseFileName], limit=200) | sort(@timestamp, order=desc)
Looks for: files being written under the backdoor plugin directories content-delivery-helper / database-optimizer, or any new .php written under wp-content/plugins/ by a web-server worker. Accomplishes: catches the on-disk backdoor drop at the moment of install.
// HUNT: New backdoor plugin files written under wp-content/plugins (Content Delivery Helper / Database Optimizer) // MITRE: T1505.003 | CONF: high FP: low COST: low // REQUIRES: FileCreateInfo / PeFileWritten with writing-process context // FALSE POSITIVES: legitimate plugin installs/updates from the WP admin UI // TUNING: alert on the two named dirs first; for the generic .php rule, allow-list scheduled update windows #event_simpleName=/PeFileWritten/i | TargetFileName=/wp-content[\/\\]plugins[\/\\](content-delivery-helper|database-optimizer)[\/\\]/i | table([@timestamp, aid, ComputerName, ContextBaseFileName, TargetFileName, UserName], limit=200) | sort(@timestamp, order=desc)
Looks for: DNS resolution of the affected vendors' CDN domains from admin workstations during the payload window — the exposure surface for the browser-side execution. FP: normal plugin usage — scope to the 2026-06-12 → 2026-06-14 window and pivot exposed admins to N4. ⚠ vendor CDN host names vary — confirm against your traffic
// HUNT: Admin workstation resolving affected-vendor CDN domains (browser-side exposure window) // MITRE: T1195.002, T1059.007 | CONF: medium FP: medium COST: low // REQUIRES: DnsRequest telemetry from WordPress admin workstations // FALSE POSITIVES: routine plugin usage outside the payload window // TUNING: constrain to 2026-06-12..2026-06-14; treat resolving admins as exposed, pivot to N4 #event_simpleName=/DnsRequest/i | DomainName=/(optinmonster|trustpulse|pushengage|awesomemotive)/i | @timestamp>=1749686400000 | @timestamp<=1749945600000 | table([@timestamp, aid, ComputerName, DomainName], limit=200) | sort(@timestamp, order=desc)
Looks for: a PHP / web-server worker spawning a command shell or scripting interpreter — the canonical web-shell / backdoor-plugin hands-on-keyboard fingerprint. Accomplishes: detects post-compromise use of the planted backdoor independent of the C2 domain.
// HUNT: Web-server worker spawning a shell / interpreter (web-shell / backdoor-plugin activity) // MITRE: T1505.003 | CONF: high FP: low COST: low // REQUIRES: ProcessRollup2 with parent-process context // FALSE POSITIVES: rare legitimate exec() in plugins (image processing, cron) — allow-list by host/path // TUNING: allow-list known plugin helper binaries; alert on bash/sh/powershell/cmd children of web workers #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/i | ParentBaseFileName=/^(php|php-fpm[0-9.]*|httpd|apache2|nginx|w3wp)(\.exe)?$/i | FileName=/^(bash|sh|dash|ksh|zsh|cmd|powershell|pwsh|wget|curl|python[0-9.]*)(\.exe)?$/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine], limit=200) | sort(@timestamp, order=desc)
CrowdStrike Custom IOA Recommendations
| IOA Name | Field Patterns | Benign Exclusions | Deployment Path |
|---|---|---|---|
| WP Backdoor — plugin drop | File write where TargetFileName matches wp-content/plugins/(content-delivery-helper|database-optimizer)/ | None — these names are attacker-specific (Detect+Block) | Endpoint Security → Custom IOA → File Creation (Detect+Block) |
| WP Worker — shell spawn | Parent php/php-fpm/httpd/nginx/w3wp; child bash/sh/cmd/powershell/python (Q6 logic) | Known plugin helpers / cron exec (allow-listed) | Endpoint Security → Custom IOA → Process Creation (Detect, then Block after tuning) |
| C2 — tidio.cc beacon | Network/DNS to tidio.cc or non-tidio.com tidio* (Q1/Q2 logic) | Legitimate tidio.com chat widget (excluded) | Custom IOC (domain) → Block; NG-SIEM scheduled search for alerting |
Machine-Readable IOC Appendix
Grouped IOC Quick-Copy
One-click blocks for network blocking, on-disk audit, identity review, and behavioral detection. Update the plugins to the cleaned versions and purge the CDN cache (the fix); the domain + on-disk + identity artifacts are the durable detections.
tidio.cc # Typosquat of tidio.com (registered 2026-04-28) — C2 / credential exfil # Block tidio.cc; ALSO hunt any tidio* domain whose registrable name is NOT tidio.com # DO NOT block tidio.com — that is the legitimate chat vendor
wp-content/plugins/content-delivery-helper # "Content Delivery Helper" backdoor wp-content/plugins/database-optimizer # "Database Optimizer" backdoor # These plugins self-hide from the WP admin plugin list — audit the FILESYSTEM, not the UI # Any unexpected plugin dir created 2026-06-12..2026-06-14 is suspect
developer_api1 # observed rogue WordPress admin customer1usx@gmail.com # email tied to the rogue admin dev_* # variant auto-created rogue admins (dev_xxxxxx) # Review wp_users / wp_usermeta for any admin-role account not in your known roster # Delete rogue admins, rotate ALL admin credentials, force re-login
# Affected Awesome Motive plugins (served tampered CDN JS): OptinMonster TrustPulse PushEngage # Payload-serving window: 2026-06-12 -> 2026-06-14 (PushEngage CDN nodes latest) # FIX: update each plugin to the cleaned post-incident version AND purge the CDN cache, # then audit admins (N4) + wp-content/plugins on disk (N3) before declaring clean.
Hardening — Tiered & Deployable
The immediate fix is to update the affected plugins to their cleaned versions and purge the CDN cache, then eradicate the planted admin + backdoor plugin. The rest reduces the blast radius of a browser-side supply-chain compromise.
- Update OptinMonster / TrustPulse / PushEngage to the cleaned versions and purge the CDN cache — M1051. Stops the tampered JS from being served.
- Delete rogue admin accounts (developer_api1 / dev_* / customer1usx@gmail.com) and remove backdoor plugins (content-delivery-helper, database-optimizer) — M1018 / M1040. Removes attacker persistence.
- Block tidio.cc (and non-tidio.com tidio* lookalikes) at DNS/proxy/Custom-IOC — M1031 / M1037. Cuts the C2/exfil channel. Do not block tidio.com.
- Rotate all WordPress admin credentials and invalidate active sessions — M1027 / M1018. The injected JS rode live admin sessions.
- Enforce a Content-Security-Policy on wp-admin restricting script sources — M1050. Constrains which CDNs can execute JS in the admin context.
- Require phishing-resistant MFA for all WordPress administrators — M1032. Limits the value of an exfiltrated admin credential.
- File-integrity monitoring on wp-content/plugins/ for unexpected writes — M1040 / M1022. Catches a future backdoor-plugin drop (Q4 logic).
- Restrict outbound egress from web servers to an allow-list — M1037. A web server beaconing to an arbitrary C2 should be impossible (Q2 logic).
- Pin/host critical admin-side JS locally or use Subresource Integrity where supported — M1051. Removes blind trust in vendor CDN content.
- Vendor / supply-chain risk review for all admin-context third-party scripts — M1016. Know which CDNs can run code in your admin sessions.
- Continuous WordPress admin-roster & plugin-inventory monitoring — M1047. Alert when an unexpected admin or plugin appears.
Containment Runbook
| Phase | Actions | Owner | Evidence |
|---|---|---|---|
| Isolate | Block tidio.cc at DNS/proxy/Custom-IOC; network-contain any web server with a Q1/Q2/Q4 hit; invalidate all WordPress admin sessions | Network + SOC L2 | Q1/Q2 rows; IOC block confirmation |
| Triage | Audit wp-content/plugins on disk (N3) and the admin roster in the WP DB (N4); pull process trees for plugin drop / shell spawn (Q4/Q6) | SOC L2 | N3/N4 findings; Q4/Q6 rows |
| Eradicate | Delete rogue admins (developer_api1 / dev_*); remove backdoor plugins; update affected plugins to cleaned versions; purge the CDN cache | IR + IT | Account deletion log; plugin removal/version |
| Recover | Rotate all admin credentials + WP salts/keys; rebuild from known-good if backdoor depth is uncertain; confirm no residual tidio.cc traffic | IR + IT | Credential rotation log; clean DNS/network |
| Harden | Enforce admin MFA + wp-admin CSP; restrict web-server egress; enable plugin-dir FIM; promote Q4 + tidio.cc to Detect+Block (§10) | Detection Eng | Policy state; IOA/IOC enabled |
Detection Coverage Map & Validation
| Technique | Behavior | CQL | IOA | Coverage |
|---|---|---|---|---|
| T1195.002 | CDN JS injection (vendor side) | — | — | Partial off-sensor; N1/N3 + vendor fix |
| T1059.007 | Tampered JS in admin browser | Q5 | — | Partial exposure-only; needs admin sensor/proxy |
| T1136 | Rogue admin creation | Q3 | — | Partial authoritative check is WP DB (N4) |
| T1505.003 | Backdoor plugin drop | Q4 | IOA-1 | Good |
| T1505.003 | Web-shell / backdoor use | Q6 | IOA-2 | Good |
| T1071.001 / T1567 | C2 / exfil to tidio.cc | Q1, Q2 | IOC | Good |
Validation gates: (1) confirm DnsRequest and NetworkConnectIP4 telemetry is flowing from your web servers (and admin workstations for Q5); (2) Q1 returns zero hits in a benign lookback unless compromised — any hit is high-priority; (3) verify the Q5 window epochs (2026-06-12..06-14 UTC) match your timezone before relying on them; (4) tune the Q6 allow-list against your plugins' legitimate exec() usage before promoting to Block; (5) run Native N3 (filesystem) + N4 (WP DB) on every affected site — the plugin self-hides from the admin UI; (6) promote Q4 + the tidio.cc IOC to Detect+Block (target FP near zero).
Hunt Summary Ticket
TITLE: Hunt - Awesome Motive CDN Supply-Chain Attack (OptinMonster/TrustPulse/PushEngage)
SEVERITY: Critical (active supply-chain compromise; ~1.2M sites exposed; rogue admin + backdoor)
SCOPE: Self-hosted WordPress sites running OptinMonster / TrustPulse / PushEngage +
their web servers and administrator workstations
HYPOTHESIS: Tampered CDN JS ran in a logged-in admin's browser, created a hidden developer_api1 /
dev_* admin and dropped a self-hiding backdoor plugin (content-delivery-helper /
database-optimizer), exfiltrating new creds to tidio.cc.
QUERIES RUN: Q1 tidio.cc DNS | Q2 worker outbound C2 | Q3 rogue-admin args |
Q4 backdoor plugin drop (IOA) | Q5 admin CDN exposure | Q6 worker shell spawn (IOA)
+ Native N1-N4 (plugin inventory, CDN script review, on-disk audit, admin roster)
DO FIRST: Block tidio.cc; run Q1 + Q4 -> escalate any hit; audit wp-content/plugins (N3) and
admin roster (N4); update plugins + purge CDN cache.
FINDINGS: <pending analyst execution>
GAPS: CDN injection is off-sensor; Q5 needs admin-workstation sensor/proxy coverage; the
authoritative rogue-admin check is the WP DB (N4), not the sensor.
ACTIONS: Update plugins; delete rogue admins + backdoor plugins; rotate admin creds; block
tidio.cc; enforce admin MFA + wp-admin CSP; promote Q4 + tidio.cc to Detect+Block.
OWNER: HuntPack
VERSION: v0.1 - 2026-06-16
Changelog
table() calls now carry an explicit row limit: the default is 200 and truncation is silent, so a capped result was indistinguishable from a complete one. Atomic-IOC sweeps (filters over 5+ hashes or C2 IPs) use limit=max so a wide infection is never silently under-scoped; behavioural hunts use limit=200, where exceeding the cap indicates the query needs tuning. Where present, event names that do not exist in the Falcon data model were corrected (e.g. ServiceInstalled is a Sysmon concept, not a Falcon event; ElfFileWritten is ELFFileWritten) — such queries could never return a row. No detection logic, fields, or IOCs changed.References
| Tier | Source | Used For |
|---|---|---|
| 1 | Patchstack — Supply-chain attack on OptinMonster/TrustPulse/PushEngage | Mechanism, rogue-admin + backdoor IOCs, tidio.cc exfil |
| 1 | Sansec — OptinMonster supply-chain attack | Compromised CDN API key, injected JS, ~1.2M sites, timeline |
| 1 | BleepingComputer — OptinMonster plugin hacked in CDN supply-chain attack | Affected vendors, PushEngage CDN nodes through 2026-06-14 |
| 2 | Security Affairs — Supply-chain attack via Awesome Motive CDN | Scope corroboration, root cause, rogue-admin + backdoor behavior |
HuntPack v0.1 · Awesome Motive CDN Supply-Chain Attack (OptinMonster / TrustPulse / PushEngage) · Generated 2026-06-16 · Defensive use only — no exploit code. The fix (update plugins to cleaned versions + purge CDN cache, delete rogue admins + backdoor plugins, rotate admin creds) closes the incident; the hunts are detection & defense-in-depth. Q5 keys on browser-side exposure and depends on admin-workstation telemetry — validate coverage in your tenant.