Visit the Wrong Site While Logged In to WordPress, Get a Backdoor
Securonix found JavaScript on hijacked sites that uses a logged-in WordPress admin's session to install a backdoored plugin that persists in mu-plugins and hides from the plugin list.
Hijacked websites are serving JavaScript that checks whether the visitor is logged in as a WordPress administrator somewhere, and if so, uses that session to install a backdoored plugin, according to Securonix Threat Research. Securonix calls the campaign TRUST#GRAFT. It’s not a WordPress vulnerability: the attack only works when an admin with plugin-install rights browses the wrong page while still signed in.
For defenders
The loader: Visitors see a fake “Just a moment” verification screen while the script fingerprints the browser, T1189 (Drive-by Compromise) and T1059.007 (Command and Scripting Interpreter: JavaScript). It also tries a ClickFix-style clipboard lure and collects cookies and token-like values from browser storage. If the browser has an active WordPress admin session, it uploads and activates a plugin through WordPress’s normal plugin screens. Securonix hasn’t said how the loader got onto the sites that serve it, or how many sites are involved.
The backdoor: The plugin calls itself “Web Media Optimizer” 2.1. On activation it copies itself to wp-content/mu-plugins/wmedia-recovery.php, so it keeps loading even if the visible plugin is deleted, T1505 (Server Software Component). It hides from the plugin list and updates, T1564 (Hide Artifacts), injects a remote script into public pages, and has a token-gated path that logs the attacker in as the first administrator. Securonix doesn’t attribute the campaign.
Hunt: Plugin upload and activation requests seconds apart in one admin session, new PHP files in mu-plugins, unfamiliar script tags on public pages, and remote URLs in options or transients.
caapman[.]me
vtevens[.]icu
gerlace[.]com
nutmann[.]club
okuneva[.]sbs
vilialobos[.]lolwmedia-recovery.php 86d775c2d5cb459541cd2b0b967fac65ce20c60e483c71c9f7e108d5ad0bd564
ads.php 2dfa9e708fdb92e5d36080065f978e33a692c0fe813a75be9c7cdff03be51b6e
wm.zip 9215d17e5138cee498bb529e69b1cc7267305136535025e9b49fe173cf648720What it means for you
If you run a WordPress site, staying logged in to your dashboard while you browse the web is the risk here. A bad page you visit in another tab can quietly install a fake plugin on your site using your own login. If you don’t manage a WordPress site, there’s nothing for you to do.
Do this now
- Use a separate browser or profile just for WordPress admin, and log out when you’re done.
- Look in
wp-content/mu-pluginsfor files you didn’t add, especiallywmedia-recovery.php, and check your plugin list for “Web Media Optimizer.” - If you find it, remove both copies, then change admin passwords and log out all sessions.
- Give plugin-install rights to as few accounts as possible.
Source article: TRUST#GRAFT: JavaScript-Compromised Sites Target WordPress Admin Browsers to Deploy a Persistent PHP Backdoor
Publisher: Securonix Threat Research (Akshay Gaikwad, Aaron Beardslee)
Published: October 2026 (exact date not stated on the page; first indexed by AlienVault OTX on Oct. 22, 2026)
URL: https://www.securonix.com/blog/trust-graft-wordpress-admin-php-backdoor/
Executive Summary
TRUST#GRAFT is Securonix’s name for an unattributed campaign; no vendor alias or named group is attached to it, and the second-stage PHP backdoor is tracked by the plugin name it uses, “Web Media Optimizer” 2.1. A JavaScript loader served from attacker domains (caapman[.]me, vtevens[.]icu, gerlace[.]com and others) runs on pages a victim visits; Securonix could not establish how the loader got onto those pages (compromised sites, injected content, malvertising or a traffic distribution system are all possible). The loader covers the page with a fake “Just a moment…” verification iframe, fingerprints the browser, solves a proof-of-work challenge, tries a ClickFix-style clipboard lure, and harvests cookies and token-like localStorage/sessionStorage values to a controller endpoint. If the browser also holds an authenticated WordPress administrator session, the script walks the normal admin workflow: it reads the upload nonce from plugin-install.php, downloads wm.zip from a /p/wm.zip path, uploads it through update.php?action=upload-plugin, and activates it through plugins.php. The plugin copies itself to wp-content/mu-plugins/wmedia-recovery.php so it survives removal, hides from the plugin list and update checks, prints a remote script tag into every public page from a controller URL (default vilialobos[.]lol/ads.php) cached in wm2_-prefixed options and transients, and exposes a token-gated action that logs the requester in as the first administrator. The objective is durable control of WordPress sites and their visitors without any WordPress vulnerability; the impact is a backdoored site that serves attacker JavaScript to its own audience and a passwordless admin login. Hunt leads, false-positive expectations, the absence of published rules, and the indicators are detailed below.
ATT&CK chain: Initial Access → Execution → Credential Access → Exfiltration → Persistence → Defense Evasion → Command and Control
Hunt Lead Grid
| Hunt Lead Level | Hunt Lead Name | ATT&CK | Risk of False Positives |
|---|---|---|---|
| 1 (Junior) | TRUST#GRAFT Infrastructure and wm.zip Retrieval Sweep | T1189 (Drive-by Compromise) | Low. The sweep anchors on six campaign domains, exact loader and /p/wm.zip URLs and the controller’s /api/v1/ hash-like paths, none of which legitimate sites use; generic /api/v1/ paths on other hosts are excluded by pairing path with domain. |
| 1 (Junior) | mu-plugins wmedia-recovery.php and wm2_ Artifact Sweep | T1505 (Server Software Component), T1564 (Hide Artifacts) | Low. Legitimate mu-plugins exist on managed hosts, so the sweep anchors on the exact file name, the plugin header “Web Media Optimizer” and wm2_-prefixed option names rather than on any new mu-plugin. |
| 2 (Pro) | Plugin Upload-and-Activate Burst From One Admin Session | T1185 (Browser Session Hijacking); source maps T1078 (Valid Accounts) | Medium. Admins do install plugins by ZIP upload, so the rule anchors on the scripted sequence (fetch of the upload page, upload and activation seconds apart with no human page views between) and on uploads outside change windows. |
| 2 (Pro) | Unexpected Remote Script in Public Pages and PHP Outbound Fetches | T1102 (Web Service) | Medium. Sites load many third-party scripts (analytics, ads, CDNs), so the rule anchors on a script origin that is not on the site’s own allowlist and on the PHP process fetching an ads.php-style controller URL. |
| 3 (Elite) | Visitor Exfiltration Followed by Admin Plugin Install | T1555.003 (Credentials from Password Stores: Credentials from Web Browsers), T1567 (Exfiltration Over Web Service), T1185 (Browser Session Hijacking) | Low. The correlation requires a POST to the campaign’s storage-exfiltration path from a client followed within minutes by a plugin upload to a WordPress site from the same client, a combination with no benign explanation. |
TRUST#GRAFT Infrastructure and wm.zip Retrieval Sweep
The loader is pulled from campaign domains as short random-named scripts (for example gerlace[.]com/0k2blyny.js, vtevens[.]icu/x9bpnmck.js and caapman[.]me/cse3g1jd.js), then talks to controller paths relative to its base URL: GET /api/v1/8e4c615 for the proof-of-work token, POST /api/v1/f659473 for the fingerprint and nonce, GET /api/v1/e81929c?tk= for the clipboard command, GET /api/v1/76584c1?e= for event reporting and POST /api/v1/6a38418 for harvested cookies and storage. When it finds an admin session, the browser itself downloads the plugin from a /p/wm.zip path on the same infrastructure (caapman[.]me and vtevens[.]icu confirmed; nutmann[.]club and okuneva[.]sbs listed as candidates). The detection logic is a retrospective sweep of proxy, secure web gateway and DNS logs for any of the six domains (caapman[.]me, vtevens[.]icu, gerlace[.]com, nutmann[.]club, okuneva[.]sbs, vilialobos[.]lol), for any URL ending in /p/wm.zip, and for the five controller paths on those hosts.
Use web proxy and DNS resolver logs from user workstations, and also outbound logs from web servers, since the backdoor fetches its controller from vilialobos[.]lol/ads.php server-side. Sweep 90 days: the infrastructure is reused and Securonix could not say how long the loader had been in place. Scope first to the workstations of people who administer WordPress sites (marketing, web and agency staff), because a hit there may mean a site they manage was backdoored. A DNS-only hit shows a visit, not an install; a hit on /p/wm.zip from a workstation means the admin pivot ran and should be escalated to a check of every WordPress site that user administers. Do not rely on blocking the domains alone: the loader’s host list rotates, and the durable artifacts are on the WordPress server, covered by the next lead.
Hunt Lead Level: 1 (Junior Analyst)
ATT&CK: Initial Access → T1189 (Drive-by Compromise) (mapping per source article); Command and Control → T1102 (Web Service) for the server-side controller fetch
Sources: “TRUST#GRAFT: JavaScript-Compromised Sites Target WordPress Admin Browsers to Deploy a Persistent PHP Backdoor”, Securonix Threat Research, Oct. 2026, https://www.securonix.com/blog/trust-graft-wordpress-admin-php-backdoor/ (source article)
mu-plugins wmedia-recovery.php and wm2_ Artifact Sweep
On activation the Web Media Optimizer plugin creates wp-content/mu-plugins/ if it does not exist and copies its own file there as wmedia-recovery.php. Must-use plugins load on every request and do not appear in the normal plugin list, so deleting the visible plugin leaves the backdoor running. The plugin also filters itself out of all_plugins, plugin action links and update responses, stores its controller URL Base64-encoded under options and transients with the wm2_ prefix (Securonix names wm2_a, wm2_src and wm2_hc as hunt strings), and checks a hardcoded token before its admin-login and controller-replacement actions. The detection logic is a file and database sweep: any file named wmedia-recovery.php under mu-plugins, any plugin directory or file whose header names “Web Media Optimizer”, any PHP file containing the constants WM2_AUTH, WM2_PREF or WM2_SRC or the Securonix-published token string, and any wp_options row whose option_name starts with wm2_ or _transient_wm2.
Run it with file integrity monitoring or EDR file-create events on Linux web servers, a direct file search on each WordPress install, and a SQL query against wp_options; hosting providers can run the same search across all customer document roots. Sweep the full current state rather than a time window, because the file persists until removed. The SHA-256 values in the appendix will match only unmodified copies; prefer the path, header and string checks, since the plugin is easy to repack. A hit means the site is compromised: preserve the files, the database and the web server logs, then remove both the visible plugin and the mu-plugins copy, delete the wm2_ options and transients, rotate every administrator password and salt (the backdoor issues admin auth cookies), and review administrator accounts. Removing only the plugin from the dashboard is the wrong response, because the mu-plugins copy stays hidden and keeps working. The sweep generalizes to any WordPress backdoor that uses mu-plugins for persistence; review every unfamiliar file in that directory.
Hunt Lead Level: 1 (Junior Analyst)
ATT&CK: Persistence → T1505 (Server Software Component); Defense Evasion → T1564 (Hide Artifacts) and T1036 (Masquerading) (mapping per source article)
Sources: “TRUST#GRAFT: JavaScript-Compromised Sites Target WordPress Admin Browsers to Deploy a Persistent PHP Backdoor”, Securonix Threat Research, Oct. 2026, https://www.securonix.com/blog/trust-graft-wordpress-admin-php-backdoor/ (source article)
Plugin Upload-and-Activate Burst From One Admin Session
The loader drives the WordPress admin like a script, not a person: GET /wp-admin/ to confirm the session, GET /wp-admin/plugin-install.php?tab=upload to read the nonce, a multipart POST to /wp-admin/update.php?action=upload-plugin carrying wm.zip, GET /wp-admin/plugins.php to read the activation link, then GET /wp-admin/plugins.php?action=activate&plugin=…&_wpnonce=…. All of it rides the administrator’s own cookies, so authentication logs show a normal, already-logged-in admin. The detection logic is a web server access-log rule that, per client IP and session cookie, flags the upload POST followed by an activate request within a short window (start at 60 seconds), with no requests for the admin page’s CSS, JavaScript and images in between, which a real browser rendering the screens would fetch. Raise severity when the Referer on those requests is a foreign site or empty, when the uploaded plugin slug is new to the site, and when the upload happens outside a change window.
Use web server or WAF access logs for wp-admin (and a WordPress activity-log plugin, if one is installed, for the “plugin installed” and “plugin activated” events with user and IP). Sweep 90 days of logs, then run it continuously. Scope to every WordPress site the organization runs or hosts. Tune by allowlisting deployment automation by its source IP and user agent (WP-CLI and CI deploys do not use the upload form), not by excluding admin users, since the attack uses real admin accounts. Disabling plugin uploads with DISALLOW_FILE_MODS on production sites removes the path entirely and is a stronger control than tuning. A hit should be treated as a compromise: confirm the plugin, then run the artifact sweep above. The rule generalizes to any cross-site attack that turns an admin’s browser into an installer.
Hunt Lead Level: 2 (Pro)
ATT&CK: Collection → T1185 (Browser Session Hijacking), our mapping for the attacker acting through the admin’s live browser session; the source article maps this step to Persistence → T1078 (Valid Accounts), which also fits because no credentials are bypassed
Sources: “TRUST#GRAFT: JavaScript-Compromised Sites Target WordPress Admin Browsers to Deploy a Persistent PHP Backdoor”, Securonix Threat Research, Oct. 2026, https://www.securonix.com/blog/trust-graft-wordpress-admin-php-backdoor/ (source article)
Unexpected Remote Script in Public Pages and PHP Outbound Fetches
Once active, the backdoor resolves a controller source (default hxxps://vilialobos[.]lol/ads.php, stored Base64-encoded and cached in a transient, with a fallback copy in the options table), fetches it with wp_remote_get using sslverify disabled or a file_get_contents fallback with peer verification off, and prints a script tag pointing to the remote JavaScript on wp_head, so every visitor of the site loads attacker code. A token-gated request can swap the controller URL and clear the cache, so the domain may change after installation. The detection logic has two parts: an external or synthetic crawl of the site’s public pages that alerts on any script src whose origin is not on the site’s approved list, and an outbound rule on the web server that flags the PHP or web server process connecting to a host that is neither a known plugin update service nor a configured API, with ads.php in the URL as a high-confidence marker.
Use a scheduled crawler or uptime monitor that captures page HTML, Content-Security-Policy violation reports if CSP report-only is enabled, and egress firewall or proxy logs from web servers. Sweep current page state for every site and 90 days of egress logs. Analytics, ad and CDN scripts will match the crawl unless the allowlist is maintained per site, so keep that list in version control and alert only on new origins. Blocking vilialobos[.]lol alone is the wrong choice because the controller is replaceable on demand; detect the injected tag and the outbound fetch instead. A new script origin on a site that has not been changed is an incident: check for the mu-plugins file and wm2_ options. A CSP with a script allowlist would stop visitors’ browsers from loading the injected script and also generalizes to other WordPress skimmers and injectors.
Hunt Lead Level: 2 (Pro)
ATT&CK: Command and Control → T1102 (Web Service) (mapping per source article)
Sources: “TRUST#GRAFT: JavaScript-Compromised Sites Target WordPress Admin Browsers to Deploy a Persistent PHP Backdoor”, Securonix Threat Research, Oct. 2026, https://www.securonix.com/blog/trust-graft-wordpress-admin-php-backdoor/ (source article)
Visitor Exfiltration Followed by Admin Plugin Install
The browser stage harvests before it pivots: it searches localStorage and sessionStorage for keys containing token, jwt, auth, _key, api, secret, session, bearer or csrf, appends up to 1,500 characters of document.cookie, and POSTs the bundle to /api/v1/6a38418 on the loader host. Only then, if an admin session exists, does it start the plugin-install sequence against the WordPress site. The detection logic is a cross-source correlation keyed on the client: a proxy or SWG record of a POST to /api/v1/6a38418 (or any of the controller paths) on a campaign domain, followed within 15 minutes by a WordPress access-log record of POST /wp-admin/update.php?action=upload-plugin from the same egress IP or user. Add a lower-severity branch for the exfiltration POST alone, since it means that browser’s stored tokens and cookies for other services have gone to the attacker even if no WordPress session existed.
This needs workstation proxy logs, WordPress or WAF access logs and an identity or IP mapping (NAT egress, VPN pool) in one SIEM; the join is on egress IP and time, refined by user where the proxy is authenticated. Run it continuously and back-test over 90 days. Shared egress IPs in offices can produce a coincidental join, so require the exfiltration POST from the same authenticated proxy user who owns the admin session where possible. Any hit is an escalation, not a tuning exercise: treat the WordPress site as backdoored and the user’s browser session material as stolen, invalidate sessions and rotate tokens for the services found in that browser’s storage, not just WordPress. The correlation generalizes to other loaders that steal browser storage and then act as the user.
Hunt Lead Level: 3 (Elite)
ATT&CK: Credential Access → T1555.003 (Credentials from Password Stores: Credentials from Web Browsers) and Exfiltration → T1567 (Exfiltration Over Web Service) (mapping per source article); Collection → T1185 (Browser Session Hijacking) for the follow-on install
Sources: “TRUST#GRAFT: JavaScript-Compromised Sites Target WordPress Admin Browsers to Deploy a Persistent PHP Backdoor”, Securonix Threat Research, Oct. 2026, https://www.securonix.com/blog/trust-graft-wordpress-admin-php-backdoor/ (source article)
Hash Appendix
No published YARA or Sigma rules: Securonix lists its own product detections and hunting query themes but no rule text.
Web Media Optimizer plugin and controller (PHP, ZIP)
SHA-256 values come from the source article. The source gives no MD5 or SHA-1; AlienVault OTX’s TRUST#GRAFT pulse holds one MD5 and one SHA-1 but does not tie them to a file name, so they are not listed here.
MD5s
(not available) # wmedia-recovery.php -> wp-content/mu-plugins/ (persistent copy of the plugin)
(not available) # ads.php -> controller script hosted at vilialobos[.]lol
(not available) # wm.zip -> plugin archive downloaded from /p/wm.zip and uploaded via update.php
SHA1s
(not available) # wmedia-recovery.php -> wp-content/mu-plugins/
(not available) # ads.php -> controller script hosted at vilialobos[.]lol
(not available) # wm.zip -> plugin archive from /p/wm.zip
SHA256s
86d775c2d5cb459541cd2b0b967fac65ce20c60e483c71c9f7e108d5ad0bd564 # wmedia-recovery.php -> wp-content/mu-plugins/ (persistent copy of the plugin)
2dfa9e708fdb92e5d36080065f978e33a692c0fe813a75be9c7cdff03be51b6e # ads.php -> controller script hosted at vilialobos[.]lol
9215d17e5138cee498bb529e69b1cc7267305136535025e9b49fe173cf648720 # wm.zip -> plugin archive from /p/wm.zip
JavaScript loaders
SHA-256 values come from the source article, which lists 16 loader hashes but does not map them to the seven loader URLs it names; MD5 and SHA-1 are not given in the source and are not mapped in OTX.
MD5s
(not available) # JavaScript loaders (16 files)
SHA1s
(not available) # JavaScript loaders (16 files)
SHA256s
19d9335e66d9d519c9068994491b1a0f8734626b5328fca9723d942b7128bc9c # JS loader (file name not mapped by source)
0a3cb24e0d0c05b544a3e32affe3ea8a4ed87c0cc90e918c10b94d3b849d76fa # JS loader (file name not mapped by source)
16f73adce28e3a33e98035a19721819ddac9cda130e6f1c337db6f8d8c2f95c6 # JS loader (file name not mapped by source)
f110e20dce8361a31332faba49e29e6afd54f8bc4913841f9bdad3cbb66c14e3 # JS loader (file name not mapped by source)
85515e25894cace49286581f9436bd2da429e05bd96d39fafe1c42fbcdfcd4e7 # JS loader (file name not mapped by source)
765525c4fabd01383ca3dd330dd4f4fbc931bea0724c12f553df41b48a96ca82 # JS loader (file name not mapped by source)
804349f8f087588b057e942f321ec2c0a677a0374e02d47f95d43196fc4cac0a # JS loader (file name not mapped by source)
4659d9648275113f7f95735d170f27f10fd6d0a4e606c5b4f6e916ddc54924ed # JS loader (file name not mapped by source)
2cac894bf2cef2232247927e18acd35280065b576c5fa030b5fbad666db0afcc # JS loader (file name not mapped by source)
eeb182444019802abb34668bd6efc7e947c1822e95c87f9a5b5288b4331400c8 # JS loader (file name not mapped by source)
2747316171bb2816b68db308162b40a47c6ddf82779d5f460a194921eb60f32c # JS loader (file name not mapped by source)
eb5a6c895d24fd08e3bbd74d7a0ea02600d3b7574b9761efb2876b671e8ddd39 # JS loader (file name not mapped by source)
3b79b342a580dd09a5e3f907e475c3131f4005be59468a59905fc289e005806d # JS loader (file name not mapped by source)
2fa9c207981e05141162b9c5cf62a86bdc6593b3a6861968e4df58f49c47da0d # JS loader (file name not mapped by source)
e98949a8370c5c3356a8e97f49a2f963a6126b917e1bc653890f8c79738c981d # JS loader (file name not mapped by source)
07955dcb5f4f80c90ede398879589f2e369eb2d84c4975d3c8adf08433783409 # JS loader (file name not mapped by source)
References Appendix
- “TRUST#GRAFT: JavaScript-Compromised Sites Target WordPress Admin Browsers to Deploy a Persistent PHP Backdoor”, Securonix Threat Research (Akshay Gaikwad, Aaron Beardslee), Oct. 2026, https://www.securonix.com/blog/trust-graft-wordpress-admin-php-backdoor/ (source article; infection chain, plugin behavior, IOCs, hashes, ATT&CK table, hunt themes)
- “TRUST#GRAFT : JavaScript-Compromised Sites Target WordPress Admin Browsers to Deploy a Persistent PHP Backdoor”, AlienVault OTX pulse, Oct. 22, 2026, https://otx.alienvault.com/pulse/6ada5f1fb2e3c0d3b77b8ceb (checked for MD5/SHA-1; none mapped to file names)
- MITRE ATT&CK Enterprise technique pages linked above, MITRE, https://attack.mitre.org/