WordPress XSS campaign plants four routes back into sites
A WordPress XSS campaign is exploiting flaws in two unrelated plugins to run malicious JavaScript when an administrator views stored customer data. Patchstack first observed the activity on October 4, 2026, targeting CVE-2026-93836 in WPC Product Bundles for WooCommerce, followed on October 5 by CVE-2026-94504 in Ninja Forms. Both attacks load the same script from imgcdn1.com, which then uses the administrator's active session to install malware and establish four separate routes back into the website. Patchstack says exploitation is active but remains limited in its telemetry, and two confirmed delivery flaws should not be treated as the final total.
Both vulnerabilities are unauthenticated stored cross-site scripting, or stored XSS, flaws. This means an attacker can save malicious browser code in a site without signing in, then wait for that code to run when an administrator opens the affected record. CVE-2026-93836 affects WPC Product Bundles for WooCommerce through version 8.6.6 and has a CVSS severity score of 7.1. Attackers supplied a quantity beginning with a valid number, followed by a script element, through the woosb_ids[…][qty] parameter. The value passed validation, remained in WooCommerce order metadata and was later displayed without adequate protection. The plugin has more than 30,000 active installations, and its changelog identifies version 8.6.7 as the security fix.
CVE-2026-94504, also rated CVSS 7.1, affects Ninja Forms through version 3.15.3, a plugin with more than 500,000 active installations. Its normal AJAX submission endpoint accepted attacker-controlled content in non-rich-text textarea fields. The legacy administrative submission editor could then display that content without safely encoding it, allowing JavaScript to run when the submission was viewed. Version 3.15.4 strengthened output escaping on that screen. Although the injected loaders were adapted to the different form and order contexts, both fetched the centralized payload at https://imgcdn1.com/fz/x.js.
Patchstack's analysis found that x.js is a 19,378-byte post-exploitation script, meaning code used after initial access has already been gained. It does not steal the administrator's cookie or require another server flaw. Because it runs within the compromised site's own browser context, requests to wp-admin automatically carry the administrator's authenticated session. The script opens privileged pages, extracts CSRF nonces, which are temporary values WordPress uses to confirm administrative actions, and submits those values through legitimate WordPress functions. HttpOnly cookie protection does not stop this because the code never needs to read the cookie directly.
Before making changes, x.js contacts the command-and-control server, or C2, at imgcdn1.com/fz/c.php with the target site's address. The response reports whether the plugin, administrator and additional persistence stages have succeeded. The script also records progress in browser Local Storage under a key beginning __xp_v9_, marking stages as plugin, admin, emer and finally all. It reports results through fetch(), sendBeacon() or an image request, giving the status message several ways to survive page navigation.
Using the administrator's session, the malware opens WordPress's plugin upload page, collects its nonce and downloads a ZIP package from the C2. The package installs as wp-smart-thumbnails and impersonates “WP Smart Thumbnails” 1.2.4 by “MediaPress Labs”. Its four files include the 20,728-byte wp-smart-thumbnails.php dropper, the 14,330-byte emer-run.php persistence installer and two tiny decoys. All carry July 2026 timestamps, predating the campaign. The main file exits when WordPress loads it normally and runs only through a direct web request, helping it appear inactive in the dashboard.
The dropper conceals its payload behind seven transformations involving Base64, XOR, reversal, ROT13, byte rotation and decompression, followed by an MD5 integrity check. Instead of using the commonly detected eval() function, it registers the dyiv:// stream wrapper and includes the decoded code through that address. The result is an approximately 37 KB graphical file manager titled “Moon, tell me if I could”. It requires no password, token or WordPress permission and can list, upload, delete, rename, create, read and save files through a JSON interface. It does not directly call system() or exec(), but its ability to write attacker-controlled files into any writable location is sufficient to install another webshell, a web-accessible tool for controlling files or executing further malicious code.
The emer-run.php component creates the more durable access. It first adds a fully privileged account with a routine-looking username selected from words such as support, updater, maintenance or backup, an @wordpress.org email address and a random 16-character password. It then writes a must-use plugin, a WordPress extension that loads automatically and cannot be disabled from the normal Plugins screen. Hooks in that file remove the account from user queries, administrator filters and displayed totals, so it remains absent from Users and is not counted. Removing the wp-smart-thumbnails plugin does not remove this hidden administrator.
A second must-use plugin creates /wp-login.php?_wplogin=. Anyone holding a valid token is silently authenticated as the site's oldest existing administrator, usually the original owner, rather than as the hidden account. Logs that record only the user ID may therefore make the session look genuine. Both must-use plugins are obfuscated with a different key and random variable names on each infected site, preventing a single file hash from identifying every copy. The installer also finds the oldest modification time in the WordPress root and applies it to the new files, defeating searches that only look for recent changes.
One successful execution therefore leaves four independent access methods: a visible administrator created with credentials from the C2, the concealed administrator, the special login URL for the oldest administrator and the unauthenticated file manager. Only the first is normally visible in WordPress. Stored XSS is particularly effective here because the attacker does not need to persuade an administrator to open a special link. The payload waits inside an ordinary order or form submission. WordPress 7.1.1 addressed a separate unauthenticated stored XSS issue in wpautop() in September 2026, illustrating that this attack model is not limited to one plugin.
The imgcdn1.com domain hosted the browser implant, victim checks, malicious plugin package, attacker-selected credentials and compromise reporting. It was registered on October 1, delegated to a Cloudflare nameserver on October 2 and first appeared in Patchstack's telemetry at 10:39 UTC on October 4. The two plugin flaws had been publicly disclosed on September 22.