Audit #28 Malicious Closed by wp.org · trunk uncleaned
Show full summary
SiteGuarding 27-plugin portfolio (2013-2020) — 15 plugins shipped siteguarding_tools.php v1.7 RCE backdoor INLINE in the plugin folder; 12 sibling plugins shipped phone-home guideline violations. wp.org closed all 27 in May-June 2020. Operator pivoted to anonymous burner accounts (audits #25, #26). Legacy C2 still operational, currently serving v2.4 backdoor (2026-04-08).
Site owners should remediate immediately. Plugin author: see the steps below to clear this label.
If you run any of these 27 plugins on your site
See the Affected plugins table below for the full slug list. To check whether any are installed across your fleet:
wp plugin list --field=name | grep -E '^(wp\-antivirus\-site\-protection|wp\-admin\-graphic\-password|grab\-youtube\-subtitle|wp\-user\-access\-notification|realtime\-seo|wp\-badbot\-protection|easy\-geo\-blocker\-and\-redirect|easy\-geo\-redirect|server\-mail\-blacklist\-checker|simple\-backup\-tool|spam\-protection\-antispam\-for\-contact\-form\-7|toxic\-links\-scanner|website\-admin\-two\-factor\-authentication|website\-blacklist\-monitor|website\-outbound\-link\-checker|website\-security\-and\-server\-performance\-analytics|wp\-admin\-access\-notification\-telegram\-sms|wp\-admin\-bruteforce\-protection\-and\-notification|wp\-admin\-protection|wp\-antivirus\-website\-protection\-and\-firewall|wp\-automatic\-plagiarism\-checker|wp\-contact\-us\-form|wp\-geo\-website\-protection|wp\-graphic\-captcha\-protection|wp\-seo\-website\-protection|wp\-text\-copy\-blocker|wp\-website\-content\-protection)$'
For each match, verify your install against the wp.org canonical and remove if compromised:
wp plugin verify-checksums <slug>
wp plugin deactivate <slug>
wp plugin delete <slug>
Patched builds for the major affected slugs are hosted at plugins.captaincore.io — see the cleanup instructions for site operators below for the full per-plugin URL list.
Affected plugins (27)
All plugins covered by this incident report. Combined exposure: 5k+ active installs across 27 slugs.
IOCs extracted (7)
| Kind | Value | Confidence |
|---|---|---|
| code_pattern | $_GET['task'] == 'remove_malware_files' |
high |
| code_pattern | $_GET['task'] == 'view_file' |
high |
| code_pattern | SITEGUARDING_SERVER_IP1 |
high |
| code_pattern | SITEGUARDING_SERVER_IP2 |
high |
| code_pattern | Task_savefile |
medium |
| domain | www.siteguarding.com |
high |
| url | https://www.siteguarding.com/ext/antivirus/index.php |
high |
Tracing SiteGuarding: A 13-Year WordPress Supply-Chain Operation Hidden in Plain Sight
Draft writeup compiled from WP Beacon audits #25 and #26 — last updated 2026-05-02
The headline
SiteGuarding (siteguarding.com — registered 2013-06-11) ran a 13-year, three-phase WordPress supply-chain operation through at least four wp.org committer accounts, controlling code on thousands of WordPress installs across multiple plugin families. The operation pivoted from overt SaaS branding (2013-2020, 27 wp.org plugins) to anonymous burner accounts (2020-2026, two more plugins) after wp.org closed the original portfolio for guideline-violations in mid-2020. Both SiteGuarding's legacy command-and-control infrastructure AND its new burner-era infrastructure are fully operational right now. Their backdoor codebase has shipped ten-plus iterations across six years; we pulled the current version (v2.4 dated 2026-04-08) directly from the live C2 with no authentication.
WP Beacon caught the operation through committer-graph analysis tying together the original @siteguarding account, the burner account @lulub5592 that surfaced in audit #25, and the second burner @dalielsam from audit #26 — all linked by shared DNS (NS1.SITEGUARDING.COM on the new C2 domain cmsplughub.com) and overlapping infrastructure on the same Leaseweb USA 198.7.59.0/24 cluster.
This is the first published documentation of the SiteGuarding operation as a connected threat actor.
Phase 1 — The overt era (2013-2020, 27 plugins)
SiteGuarding registered the wp.org account @siteguarding on 2013-10-02, four months after registering the company domain. Over the next seven years they shipped 27 plugins across security, scanning, and SEO categories:
| Plugin | First seen | Last update | Active installs at closure |
|---|---|---|---|
| wp-antivirus-site-protection | 2014-05-17 | 2018-06-11 (v7.5.4) | 4,000+ |
| wp-admin-graphic-password | — | (8 versions) | 300+ |
| wp-user-access-notification | — | (8 versions) | 100+ |
| grab-youtube-subtitle | — | (5 versions) | 100+ |
| realtime-seo | — | (10 versions) | 80+ |
| wp-badbot-protection | — | (3 versions) | 40+ |
| wp-geo-website-protection | — | 2020-05-08 (v2.9.1, 30 versions) | not snapshotted |
| wp-admin-protection | — | (13 versions) | not snapshotted |
| wp-graphic-captcha-protection | — | (4 versions) | not snapshotted |
| 18 others | — | (1-4 versions each) | <10 each |
Most-installed: wp-antivirus-site-protection (~85% of the install base). The other 26 were small adjacent utilities.
What the portfolio plugins actually did — two distinct threat tiers
Cross-portfolio code review (greppable IOCs across all 27 local git repos) revealed the portfolio splits into two threat tiers. Both share the same C2 infrastructure, both were closed in the same wp.org sweep, both were operated by the same accounts — but the in-plugin code shape differs significantly:
#### Tier A — Direct supply-chain backdoor (15 plugins)
These plugins ship siteguarding_tools.php v1.7 (482 lines, identical file, md5 3eddf6d18214d0d612809efd585a2471) bundled inline inside the plugin folder. Installing any of these 15 plugins instantly plants a web-accessible RCE backdoor at /wp-content/plugins/<slug>/siteguarding_tools.php. The file:
- Has no
if (!defined('ABSPATH')) exit;guard — directly web-accessible without WordPress bootstrap - Accepts unauthenticated requests from operator IPs
185.72.157.169-172(Polish hosting at support.pl, the v1.7-era control plane) - Falls back to RSA-PGP-signed
task_pgpparameter for non-allowlisted callers - Exposes
Task_savefile(write arbitrary file under WEBSITE_ROOT),Task_showfile(exfiltrate any file),Task_download(stream-download),Task_includefile(write attacker PHP to a.tmpcodefile theninclude()it — full RCE),Task_fileinfo(recon) - Has its own
updateaction that fetches a fresh backdoor fromsiteguarding.com/ext/panel_api/index.php(the same self-update mechanism documented in audit #25 that's currently shipping v2.4)
The 15 Tier A plugins:
easy-geo-blocker-and-redirect easy-geo-redirect
grab-youtube-subtitle realtime-seo
simple-backup-tool toxic-links-scanner
website-blacklist-monitor website-outbound-link-checker
website-security-and-server-performance-analytics
wp-admin-graphic-password wp-admin-protection
wp-badbot-protection wp-contact-us-form
wp-geo-website-protection wp-user-access-notificationCombined install base for Tier A at closure: ~880 active installs (mostly small plugins; flagship is in Tier B). Each install was a direct supply-chain backdoor — the operator could fetch https://victim.example/wp-content/plugins/<slug>/siteguarding_tools.php from any of the four allowlisted IPs and execute arbitrary PHP. No further deployment step required.
#### Tier B — Phone-home guideline violation only (12 plugins)
These plugins call siteguarding.com for legitimate-looking SaaS-plugin features (license check, remote scan, update info) but do NOT bundle siteguarding_tools.php inline. Inspecting the flagship wp-antivirus-site-protection 7.5.4 (50 versions of git history reconstructed):
// antivirus.php:14
define('SITEGUARDING_SERVER', 'http://www.siteguarding.com/ext/antivirus/index.php');
// referenced 9+ times in calls like:
$link = SITEGUARDING_SERVER.'?action=do_remote_scan&remote_id='.$remote_do_id;
$link = SITEGUARDING_SERVER.'?action=licenseinfo&type=json&data=';
$link = SITEGUARDING_SERVER.'?action=updateinfo&data=';
$link = SITEGUARDING_SERVER.'?action=getreport_ver2&data='.$post_data;The 12 Tier B plugins:
server-mail-blacklist-checker, spam-protection-antispam-for-contact-form-7,
website-admin-two-factor-authentication, wp-admin-access-notification-telegram-sms,
wp-admin-bruteforce-protection-and-notification,
wp-antivirus-site-protection (FLAGSHIP — 4,000+ active installs at closure),
wp-antivirus-website-protection-and-firewall, wp-automatic-plagiarism-checker,
wp-graphic-captcha-protection, wp-seo-website-protection,
wp-text-copy-blocker, wp-website-content-protectionCombined install base for Tier B at closure: ~3,810 active installs (dominated by the flagship at 4,000+). The wp.org policy violation here is undisclosed phone-home: WordPress.org plugin guidelines require explicit user opt-in for any external service calls. SiteGuarding's Tier B plugins phoned home unconditionally, embedded the API endpoint as a hardcoded constant, and offered the user no opt-out.
The flagship wp-antivirus-site-protection had a separate "consent-based remote management tool installation" UX flow that asked the user to opt in to dropping siteguarding_tools.php into WordPress root — a different delivery shape than the inline-bundled Tier A plugins. Users who clicked through that flow ended up with the same backdoor file in ABSPATH rather than /wp-content/plugins/<slug>/.
#### Counterintuitive distribution choice
The flagship — wp-antivirus-site-protection at 4,000+ installs (85% of the portfolio's install base) — is in Tier B. The 15 plugins shipping the inline backdoor were almost all small adjacent utilities (most under 100 installs each, several under 10). The operator deliberately concentrated direct-backdoor distribution in lower-profile plugins where code review by independent security researchers would be less likely. The headline product used the consent-based path; the backwater plugins shipped the backdoor inline.
#### wp.org closure timeline
Across the May-June 2020 wp.org review wave, all 27 plugins were closed in a 32-day window with closed_reason='guideline-violation':
2020-05-04 easy-geo-blocker-and-redirect, toxic-links-scanner,
wp-antivirus-website-protection-and-firewall (3 plugins)
2020-06-03 website-security-and-server-performance-analytics, realtime-seo (2 plugins)
2020-06-05 the remaining 22 pluginsThe wp.org review team likely caught the inline-bundled siteguarding_tools.php in some Tier A plugins during the review wave and closed adjacent Tier B plugins from the same author for the looser "undisclosed phone-home" pattern. Either way, the entire portfolio was closed in 32 days.
The closure was apparently silent — searching public WordPress security trackers (Wordfence, Patchstack, WPScan), security-blog archives, news coverage, and the wp.org Plugin Review Team's own announcements yielded zero documentation of the 2020 mass closure. SiteGuarding lost their wp.org distribution channel quietly.
A second SiteGuarding wp.org account
Building local git histories for all 27 plugins surfaced a SECOND committer beyond @siteguarding: @sgdevteam authored most of the trunk-only commits in 2019-2020 across 8 plugins:
easy-geo-redirect realtime-seo
simple-backup-tool website-blacklist-monitor
wp-admin-access-notification-telegram-sms
wp-automatic-plagiarism-checker
wp-badbot-protection wp-website-content-protectionMultiple of these are dated 2020-06-01 — four days before wp.org's mass closure. The team account looks like it was making last-minute commits trying to stay ahead of the looming review action.
Phase 2 — The pivot (2020-mid-2025)
wp.org closed the SiteGuarding portfolio on 2020-06-05. Twenty-six days later (2020-07-01), a new wp.org account was registered: @lulub5592, display name "CaptchaMaster". No bio, no website, no employer, no social links, no portfolio history.
Five months after that, on 2020-12-03, @lulub5592 published a single plugin: wp-advanced-math-captcha. To casual inspection, an unrelated indie WordPress captcha plugin from a new author. From day one, the plugin shipped with wp-math-captcha.dat — a zlib-compressed PHP dropper that, when loaded, decoded a base64 blob and wrote siteguarding_tools.php into the WordPress root. The dropper hardcoded the C2 endpoint as apitest.siteguarding.com/plugin_api/index.php, deleted itself after planting the backdoor, and POSTed the install's URL back to the C2 to register the new infection. The dropped backdoor v1.7 was internally dated 20 March 2020 — the same code SiteGuarding had been distributing through the consent-based path in their original antivirus plugins, just relocated to a covert delivery vehicle.
The plugin grew slowly over the next four years. Six thousand active installations by April 2026. Then, on 2025-11-16, @lulub5592 added a second malicious primitive: includes/advert-test-codes.php. A 32KB class whose only purpose is to nag the WordPress admin to install another specific plugin from wp.org via an admin_post_advrec_install_plugin handler. The hardcoded target slug? image-optimizer-x.
Phase 2.5 — The second burner
image-optimizer-x was launched on wp.org by a different account, @dalielsam (display name "Daniel X"). Same anonymity profile: no bio, no website, no portfolio history. The dalielsam account had been registered on 2022-11-17 — two and a half years before the plugin debuted in May 2025, plenty of buffer to age the account.
For the first six months, image-optimizer-x was a clean image optimizer (472-line main file, no C2 wiring). On 2025-12-16 — exactly 30 days after lulub5592 added the forced-install primitive — @dalielsam shipped v1.3.2 with a 981-line companion file: CMSPlughubAPI_LicenseValidator.php. The validator hardcodes:
private $api_base_url = 'https://api.cmsplughub.com';
private $verify_endpoint = '/verify.php';
private $updater_endpoint = '/updater.php';
private $rsa_private_key_primary = '-----BEGIN PRIVATE KEY-----...'; // 2048-bit
private $rsa_private_key_secondary = '-----BEGIN PRIVATE KEY-----...'; // 512-bitTwo embedded RSA private keys (a meaningless construct for legitimate licensing — public keys would suffice; private keys are for bidirectional authenticated control) and a generic downloadFile($url, $destination) primitive wrapped as a "GeoIP database updater". The plugin loads the validator on every admin request, calls home to api.cmsplughub.com, and writes whatever the C2 returns to a fixed local path.
cmsplughub.com was registered on 2025-02-11 — eighty-six days before image-optimizer-x launched on wp.org. Purpose-built infrastructure staged in advance.
The chain became operational on 2025-12-16: lulub5592's plugin pushes users to install dalielsam's plugin; dalielsam's plugin pulls instructions from cmsplughub.com.
The DNS smoking gun
cmsplughub.com was the chain's only public-looking infrastructure surface. Both wp.org accounts (@lulub5592, @dalielsam) had been built over years to look unrelated, with staggered creation dates and zero overlapping metadata. The architectural style of v1.3.2's validator was different enough from the older .dat dropper that, considered in isolation, the two campaigns might pass for separate operators using similar primitives.
But the DNS record gave it away:
$ dig +short NS cmsplughub.com
ns1.siteguarding.com.
ns2.siteguarding.com.
$ dig +short A cmsplughub.com
198.7.59.167
$ dig +short A siteguarding.com
198.7.59.167cmsplughub.com not only uses SiteGuarding's nameservers — its A record resolves to the same IP address as siteguarding.com itself. Reverse DNS:
$ dig -x 198.7.59.167 +short
server2.siteguarding.com.
hosting2.siteguarding.com.The supposedly-independent licensing service api.cmsplughub.com lives on a host literally named server2.siteguarding.com. Both domains are colocated in the same Leaseweb USA hosting account. The operator didn't even try to hide it at the rDNS layer.
The C2 is alive and being actively maintained
Both C2 endpoints respond right now to anonymous requests:
GET https://api.cmsplughub.com/updater.php?unique_id=image-optimizer-x&file=geo.mmdb&domain=example.com&md5=00000000000000000000000000000000
→ 9.2MB binary (real MaxMind GeoIP database, MaxMind.com end-marker present)
GET https://api.cmsplughub.com/updater.php?unique_id=wp-advanced-math-captcha&file=geo.mmdb&domain=example.com&md5=00000000000000000000000000000000
→ same binary payload — the C2 backend RECOGNIZES BOTH burner plugins as valid clients
GET https://api.cmsplughub.com/updater.php?unique_id=any-other-slug&...
→ {"status":"error","reason":"Wrong plugin unique_id: any-other-slug"}The C2 maintains an explicit allowlist of valid plugin IDs. We probed 30+ candidate slugs (the original 27 SiteGuarding portfolio + a dozen guesses at sibling burner names). Only image-optimizer-x and wp-advanced-math-captcha are recognized. The new C2 was purpose-built specifically for this two-burner operation; the older 27 plugins still talk to the legacy C2.
That legacy C2 is also still operational — and serving fresh malware updates:
GET https://www.siteguarding.com/ext/panel_api/index.php?action=update
→ {"md5":"36085499a539d4543b1ec0f59f1ad0c7", "b64content":"PD9waHAK..."}Decoding the base64 payload yields siteguarding_tools.php version 2.4 dated 2026-04-08 — published one day after wp.org closed both burner plugins on 2026-04-07. That's not an old artifact still reachable; it's the operator visibly continuing development the day after a major disclosure event.
Six years of malware development
The audit #25 dropper bundled siteguarding_tools.php v1.7 (dated 2020-03-20). The live C2 is shipping v2.4 (dated 2026-04-08). Diffing the two versions:
| v1.7 (March 2020) | v2.4 (April 2026) | Change | |
|---|---|---|---|
| File size | 482 lines / 13.8K | 819 lines / 24.8K | +70% |
| md5 | 3eddf6d18214d0d612809efd585a2471 | 36085499a539d4543b1ec0f59f1ad0c7 | (live samples preserved) |
| Allowlisted control IPs | 185.72.157.169-172 (4 IPs, Polish hosting at support.pl) | 198.7.59.167, 198.7.59.168 (2 IPs, Leaseweb USA — same cluster as cmsplughub.com) | Operator's control plane migrated |
| Hostname-based auth | not present | NEW: any caller whose reverse DNS ends in siteguarding.com (excluding "hosting") is auto-authenticated | New auth bypass mechanism |
| Push-update channel | manual update action only | Operator passes latest_ver + latest_md5 request params; backdoor self-fetches and overwrites | Fleet-update capability |
| Tasks | savefile, showfile, download, includefile, fileinfo (5) | + deletefile, copyfile (7) | New file-manipulation primitives |
| Path validation | none | new Validate_Path() defensive check | Operational hardening |
| Self-fingerprint in ping | absent | reports WEBSITE_ROOT (absolute disk path), self_md5, AND contents of webanalyze/website-security-conf.php (operator's panel credentials from prior installs) | Telemetry + cred-exfil |
| Persistence redundancy | manual | every ping copies the backdoor to webanalyze/siteguarding_tools.php if missing or smaller; recovery action restores root copy from the webanalyze copy | Self-healing persistence |
The 2026-era backdoor is mature, actively-maintained malware code. Not a dormant 2020 artifact still floating around — real ongoing software development happening on this codebase.
The most significant change is the operational shift: the v1.7 control plane was on Polish hosting (Support.pl sp. z. o. o., RIPE region) at four sequential IPs; v2.4 collapsed that to two IPs at the SAME Leaseweb USA host that runs cmsplughub.com. Single hosting account now operates: legacy backdoor C2 frontend, cmsplughub validator C2, AND the operator's static control plane. Operationally tighter, also a single takedown target.
Plus: the new hostname-based auth bypass means the operator can promote new control IPs by adding subdomain rDNS entries to siteguarding.com's zone — no code change, no IP allowlist update, no PGP key rotation needed. Production-quality fleet management for malware ops.
Implications
5+ years of historical SiteGuarding-portfolio installs are STILL controllable. Any WordPress site that ran one of the 27 closed plugins between 2013-2020 may still have siteguarding_tools.php (or its webanalyze/ backup copy) in its WordPress root. Those backdoors poll siteguarding.com/ext/panel_api/ on operator schedule, and the C2 is serving fresh tasks today. Many of those sites are likely no longer monitored — small-business or hobbyist sites that installed an antivirus plugin in 2017, lost interest in active security tooling, and never noticed the plugin had been closed in 2020 or that a siteguarding_tools.php had been planted in their WordPress root years earlier.
The wp.org closure response is incomplete by design. wp.org can stop distributing a plugin, but it can't reach into existing installations and pull files out. For plugins that drop files outside the plugin directory (siteguarding_tools.php in WP root, or future image-optimizer-x update payloads written to assets/), the closure is a "stop new infections" action only. Existing installs need active remediation.
This isn't a one-off opportunistic compromise. This is a 13-year operation by an actor that:
- Built a 27-plugin SaaS portfolio and operated it openly for 7 years
- Survived a major wp.org policy enforcement action by pivoting to anonymous burner accounts within 26 days
- Maintained the legacy attack infrastructure continuously across the 6-year burner era
- Engineered coordinated 30-day rollouts between sibling accounts in 2025
- Continues active malware development post-disclosure (v2.4 published one day after wp.org's April 2026 closure)
- Owns four wp.org accounts, three domains (siteguarding.com, cmsplughub.com, safetybis.com), and infrastructure in two regions (Leaseweb USA, plus historic Polish hosting at support.pl)
Cleanup checklist for affected sites
If your site has ever run any of these plugins, treat as compromised until proven otherwise:
Phase 1 portfolio (2013-2020 era, all closed in May-June 2020 by wp.org):
- wp-antivirus-site-protection, wp-antivirus-website-protection-and-firewall
- wp-admin-protection, wp-admin-bruteforce-protection-and-notification, wp-admin-graphic-password
- wp-graphic-captcha-protection, wp-text-copy-blocker, wp-website-content-protection
- wp-geo-website-protection, wp-seo-website-protection, wp-user-access-notification
- wp-admin-access-notification-telegram-sms, wp-badbot-protection
- wp-contact-us-form, wp-automatic-plagiarism-checker
- spam-protection-antispam-for-contact-form-7
- realtime-seo, grab-youtube-subtitle, simple-backup-tool
- easy-geo-blocker-and-redirect, easy-geo-redirect
- toxic-links-scanner, website-outbound-link-checker, website-blacklist-monitor
- website-admin-two-factor-authentication
- server-mail-blacklist-checker
- website-security-and-server-performance-analytics
Phase 2 burner accounts (2020-2026 era, both closed April 2026):
- wp-advanced-math-captcha (audit #25)
- image-optimizer-x (audit #26)
Remediation steps:
1. Search WordPress root recursively for siteguarding_tools.php and webanalyze/siteguarding_tools.php. Delete both. The presence of either indicates the operator has had RCE on this site at some point. 2. Look for the webanalyze/ directory under WP root. It may also contain website-security-conf.php (operator's panel-login credentials previously exfiltrated). Delete the entire directory. 3. Search for files matching the v2.4 backdoor md5 (36085499a539d4543b1ec0f59f1ad0c7) or v1.7 (3eddf6d18214d0d612809efd585a2471). Older versions (v1.0-v1.6, v2.0-v2.3) likely exist in the wild as well — anything matching the siteguarding_tools.php filename should be presumed malicious. 4. Block outbound traffic at the firewall to: siteguarding.com, www.siteguarding.com, apitest.siteguarding.com, .siteguarding.com, cmsplughub.com, api.cmsplughub.com, safetybis.com. Block by hostname rather than IP — the operator can rotate IPs via the rDNS-based auth bypass. 5. Block outbound to the IP cluster 198.7.59.0/24 (Leaseweb USA, currently hosts the operator's control plane) and 185.72.157.0/24 (Polish, legacy backdoor allowlist). 6. Audit Users → All Users for any unfamiliar admin accounts. The siteguarding_tools.php Task_savefile primitive can write arbitrary files; the Task_includefile primitive can execute arbitrary PHP — combined, the operator can create new admin accounts at will. 7. Rotate WordPress admin passwords, database credentials, and SFTP/SSH keys. Per audit #25 disclosures (wp-config.php size > 9KB is a tell, fake wp-comments-posts.php typosquat in WP root, generic admin names like officialwp/superadmin), if any of these markers are present the operator likely already has persistence beyond just the dropped backdoor. 8. For sites that ran image-optimizer-x specifically, also check wp_options for image_optimizer_x_ rows (iox_lic, iox_lic_status, iox_lic_data) — these may contain RSA-encrypted state from the cmsplughub C2. Delete after uninstall.
Indicators of compromise
Domains:
- siteguarding.com, www.siteguarding.com (legacy C2 frontend, currently operational)
- apitest.siteguarding.com (2020-era inform endpoint, currently operational)
- cmsplughub.com, api.cmsplughub.com, www.cmsplughub.com (2025-2026 burner C2)
- safetybis.com (sibling C2, NS = NS1/NS2.siteguarding.com)
- server2.siteguarding.com, hosting2.siteguarding.com (rDNS for 198.7.59.167)
URLs:
- https://www.siteguarding.com/ext/panel_api/index.php (legacy backdoor C2 — task delivery + auto-update)
- https://www.siteguarding.com/ext/antivirus/index.php (Phase-1 antivirus phone-home — referenced by wp-antivirus-site-protection)
- https://api.cmsplughub.com/verify.php (Phase-2 license verification)
- https://api.cmsplughub.com/updater.php (Phase-2 file fetch primitive)
- https://apitest.siteguarding.com/plugin_api/index.php?action=inform (Phase-2 dropper inform)
File hashes:
36085499a539d4543b1ec0f59f1ad0c7(siteguarding_tools.php v2.4, 2026-04-08, 24,851 bytes)3eddf6d18214d0d612809efd585a2471(siteguarding_tools.php v1.7, 2020-03-20, 13,888 bytes)
Filenames:
siteguarding_tools.php(the dropped backdoor, in WP root orwebanalyze/)webanalyze/website-security-conf.php(panel credentials — exfiltrated on every backdoor ping)wp-math-captcha.dat,wp-math-captcha.dat.tmp(v1.7 dropper file in wp-advanced-math-captcha)includes/advert-test-codes.php(forced-install primitive in wp-advanced-math-captcha post-2025-11)CMSPlughubAPI_LicenseValidator.php(C2 validator in image-optimizer-x post-2025-12)
Code patterns:
SITEGUARDING_SERVERconstantsiteguarding_tool_code(dropper variable name)ADVREC_TARGET_PLUGIN,ADVREC_AdverPluginRecommendation(forced-install class)CMSPlughubAPI_LicenseValidator(validator class)Task_includefile,Task_savefile,Task_showfile,Task_download,Task_fileinfo,Task_deletefile,Task_copyfile(backdoor task functions)$allowed_IPs,task_pgp,PGP_decrypt,rsa_private_key_primary,rsa_private_key_secondary(auth primitives)- IP literals:
185.72.157.169,185.72.157.170,185.72.157.171,185.72.157.172(legacy allowlist),198.7.59.167,198.7.59.168(current allowlist) - DNS infrastructure:
NS1.SITEGUARDING.COM,NS2.SITEGUARDING.COM
wp.org committer accounts (all SiteGuarding-controlled):
@siteguarding— Phase 1, 27 plugins (2013-2020), all closed@sgdevteam— Phase 1, internal team account, surfaced on 8+ portfolio plugins@lulub5592— Phase 2 burner #1 (2020-2026), single pluginwp-advanced-math-captcha, closed 2026-04-07@dalielsam— Phase 2 burner #2 (2025-2026), single pluginimage-optimizer-x, closed 2026-04-07
Source materials
- WP Beacon audit #25:
wp-advanced-math-captcha— full forensic writeup of the post-2020 burner, dropped backdoor analysis (v1.7), forced-install primitive - WP Beacon audit #26:
image-optimizer-x— second burner, CMSPlughub side-channel C2, embedded-RSA-keys analysis - WP Beacon audit #27 (in progress): SiteGuarding 27-plugin portfolio (2013-2020), this writeup
- Local git mirrors: 27/27 SiteGuarding portfolio plugins reconstructed at
~/Documents/WP.org/git/<slug>/(~191MB across all repos) - Live malware sample:
siteguarding_tools.phpv2.4, pulled fromhttps://www.siteguarding.com/ext/panel_api/index.php?action=update
Coverage gap
This operation has had no prior public attribution or coverage:
- The 2020 mass closure of the 27-plugin portfolio was apparently silent — no contemporaneous coverage from WP.org's Plugin Review Team, no security blog writeups, no entries in Wordfence/Patchstack/WPScan vulnerability databases attributing it to SiteGuarding, no CVE assignments
- The 2026 supply-chain wave that took down both burner plugins on 2026-04-07 was widely covered (TechCrunch, Cybernews, designstouch.com, rswebsols.com, anchor.host, gbhackers.com) — but the coverage focused on adjacent campaigns from the same wave (anadnet/scroll-top, EP/Essential Plugin / "Kris" buyer via Flippa, the wp-advanced-math-captcha
.datdropper). The SiteGuarding lineage going back to 2013 — and the cmsplughub.com side-channel C2 — went undocumented. - The continuous v2.4 development of the backdoor codebase post-disclosure has likewise gone unnoticed.
This writeup is the first to connect SiteGuarding's overt 2013-2020 wp.org plugin presence with the 2020-2026 anonymous-burner phase, and the first to document cmsplughub.com as an active C2.
---
Appendix A — Corporate structure: SafetyBis Ltd. (and what it became)
The 2014-era plugin headers cite a registered legal entity. From wp-antivirus-site-protection v1.2 (2014-05-17, the first published version of the flagship):
Author: SiteGuarding.com (SafetyBis Ltd.)SafetyBis Limited is a real Cyprus company:
| Field | Value |
|---|---|
| Cyprus Registry # | HE 232905 |
| Incorporated | 2008-07-01 |
| Status | DISSOLVED 2016-01-11 |
| Registered address | Ευαγόρα Παπαχριστοφόρου 18, PETOUSSIS BROS BUILDING, Floor 3, 3030, Limassol, Cyprus |
| Director | DRAFIELO LIMITED (Cyprus HE 245565) |
| Secretary | DRAFIELO LIMITED |
| DRAFIELO LIMITED's Director | ROBIDOUX EQUITIES LTD. |
| DRAFIELO LIMITED's other affiliations | ~125 Cyprus companies |
Layered Cyprus nominee structure: SafetyBis Ltd → DRAFIELO LIMITED (corporate nominee director) → ROBIDOUX EQUITIES (the next layer up). The actual beneficial owner is shielded behind multiple corporate layers — classic Cyprus offshore privacy pattern. DRAFIELO LIMITED is a nominee-director service hosting hundreds of unrelated entities; tracing further would require purchased Cyprus registry reports.
What the dissolution means
SafetyBis Ltd. dissolved on 2016-01-11 — but the SiteGuarding operation kept running for another 10 years under the same brand:
- siteguarding.com stayed registered (currently paid through 2031-06-11)
- safetybis.com stayed registered, but was repurposed — the current homepage positions the brand as "Web Development Agency | Cyprus Web Development", not security services. Same Limassol DNA, different stated business
- 27 wp.org plugins kept shipping new versions under
@siteguardingand@sgdevteamaccounts through 2020 (4 years post-dissolution) - siteguarding_tools.php backdoor kept being maintained — currently at v2.4 dated 2026-04-08 (10 years post-dissolution)
- Two burner wp.org accounts (
@lulub5592from July 2020,@dalielsamfrom November 2022) launched after the dissolved Cyprus entity — no public attribution to any legal vehicle
Plugin author attribution survey
Across the 27-plugin portfolio, the Author: header in each plugin's main PHP file shows multiple brand variants. Crucially, the SafetyBis Ltd. attribution is dropped after the 2016 dissolution:
| Author header (verbatim) | Plugin count | Era |
|---|---|---|
SiteGuarding.com (SafetyBis Ltd.) | 17 | Pre-2016 dissolution |
Technology Solutions Code (SafetyBis Ltd.) | 1 (grab-youtube-subtitle) | Pre-2016 |
SiteGuarding.com (no Cyprus entity) | 5 | Post-2016 |
SiteGuarding (no .com, no entity) | 3 | Post-2016 |
SEOGuarding | 1 (realtime-seo) | Sub-brand |
Earliest portfolio commit: 2014-03-03 (wp-admin-protection). Latest: 2020-06-01 (multiple plugins, last commits 4 days before wp.org closure). The two-brand pattern (SiteGuarding for security, SEOGuarding for SEO products) was active alongside the primary brand throughout.
"Since 2005" claim
The 2014 wayback snapshot of siteguarding.com displays "since 2005" branding. SafetyBis Ltd. wasn't incorporated until 2008-07-01 — the brand pre-dates the Cyprus entity by 3 years. Either:
- An earlier legal entity existed (Ukraine? Poland? UK?) that the brand carried over from
- The "since 2005" claim is marketing-only with no incorporated business behind those years
- The brand was acquired in 2008 by SafetyBis from an earlier owner
Per cybersecurityintelligence.com, SiteGuarding is currently listed as "London United Kingdom" — but no UK Companies House entity matches. Likely either a third-party data feed inaccuracy or a UK presence operating outside Companies House registration.
Continued infrastructure ownership post-dissolution
Despite SafetyBis Ltd. being formally dissolved 10 years ago, the operation's domain portfolio is still actively managed:
| Domain | Created | Currently owned by | Currently paid through |
|---|---|---|---|
| siteguarding.com | 2013-06-11 | (privacy-masked Namecheap) | 2031-06-11 |
| safetybis.com | 2007-06-27 | (GDPR-masked, Cyprus state code) | unknown |
| cmsplughub.com | 2025-02-11 | (privacy-masked, Iceland) | unknown |
All three share NS1.SITEGUARDING.COM / NS2.SITEGUARDING.COM for nameservers. All three resolve to or are colocated on the Leaseweb USA 198.7.59.0/24 cluster. The operator either:
- Personally maintained domain renewals after SafetyBis dissolved (paying out-of-pocket since 2016)
- Transferred domains to a new legal entity that's not publicly disclosed
- Operates the domains under nominee names with no formal corporate owner
Implications for attribution
This isn't an anonymous criminal operation. It's:
- A real Cyprus-registered company with traceable corporate history (2008-2016)
- A public commercial brand with G2 / Trustpilot reviews and paying customers
- A 13-year continuous operation under the SiteGuarding name
- Currently operating WITHOUT a publicly-attributed legal entity (since the 2016 SafetyBis dissolution)
The post-2016 era — covering more than half the operation's lifespan — is corporate-veil-less. There's no registered business answering for the SiteGuarding brand today. Customers paying for siteguarding.com services since 2016 have been transacting with an entity that doesn't legally exist.
Combined with the malware findings: the dissolved Cyprus entity may have been the legitimate-services arm; the post-dissolution operation may be the malware-only arm operated by the same principals without legal cover. Or the dissolution may have been deliberate corporate restructuring to shed liability before the malware operation scaled. Without purchased Cyprus registry deep-dive reports (€65 per the cyprusregistry.com note) or further pivoting on DRAFIELO LIMITED's 125 affiliated entities, the question of WHO owns the SiteGuarding brand today remains open.
---
Appendix B — Subdomain footprint of siteguarding.com
TLS certificate Subject Alternative Names:
DNS:cpanel.siteguarding.com
DNS:cpcalendars.siteguarding.com
DNS:cpcontacts.siteguarding.com
DNS:mail.siteguarding.com
DNS:siteguarding.com
DNS:webdisk.siteguarding.com
DNS:webmail.siteguarding.com
DNS:www.siteguarding.comStandard cPanel-managed hosting subdomains, plus the operational siteguarding.com and www.siteguarding.com. No custom subdomains exposed — the operational endpoints (apitest.siteguarding.com, the *hosting2.siteguarding.com rDNS used by the rDNS-auth-bypass) are covered by separate certs or wildcard configurations.
The cpanel/webmail subdomain pattern indicates standard shared-hosting cPanel deployment — not a custom security operations stack.
---
Appendix C — Flagship plugin (wp-antivirus-site-protection) malware-evolution timeline
50 versions across 4 years (2014-2018), then a 2-year dormancy until wp.org's 2020 mass closure. Compiled from local git reconstruction of every released version.
Version-by-version growth
| Date | Version | LOC | Files | Significance |
|---|---|---|---|---|
| 2014-05-17 | 1.2 | 1,210 | 3 | First wp.org release. Already ships SITEGUARDING_SERVER constant pointing to siteguarding.com/ext/antivirus/index.php. "Register your website on SiteGuarding.com" opt-in flow + PRO upsell + license check from day one. |
| 2014-05-29 | 2.0 | 1,411 | 3 | Added getreport_ver2 action. New sgantivirus.class.php and antivirus.class.php files. Architecture matures from monolithic to class-based. |
| 2014-05-30 | 2.0.1 | 1,808 | 4 | New sgantivirus.class.php split out. |
| 2014-07-28 | 3.0 | 2,468 | 4 | Major scan-engine rewrite (+396 LOC). |
| 2014-09-26 | 4.0 | 3,080 | 4 | Heuristic detection added (+351 LOC). |
| 2015-04-07 | 5.0 / 5.0.1 | 4,745 | 6 | Files jumped 4→6 (license + scanner architecture rewrite). |
| 2016-04-06 | 6.0 | 5,705 | 7 | Added sgantivirus.login.php (login-protection feature). New updateinfo action. |
| 2016-10-07 | 6.5 | 7,740 | 7 | Switched from raw file_get_contents to wp_remote_*. LOC nearly doubled in one release (5,705 → 7,740). |
| 2017-01-03 | 7.0 | 8,995 | 7 | SITEGUARDING_SERVER_IP1 (185.72.157.169) and SITEGUARDING_SERVER_IP2 (185.72.157.170) HARDCODED in main plugin file. First time the operator's static control-plane IPs appear in the plugin code itself. |
| 2017-05-12 | 7.5 | 14,624 | 10 | Major architecture rewrite. LOC nearly doubled again (9,115 → 14,624). New antivirus.php file. Added do_remote_scan action. Last touch of SITEGUARDING_SERVER references — code stabilized here. |
| 2017-12-21 | 7.5.1 | 14,641 | 10 | Minor maintenance (+17 lines). |
| 2018-05-04 | 7.5.3 | 14,659 | 10 | Minor maintenance (+18 lines). |
| 2018-06-11 | 7.5.4 | 14,659 | 10 | Final release. Then dormant 2 years until wp.org closure. |
| 2020-06-05 | — | — | — | wp.org closes the plugin in the portfolio-wide guideline-violation sweep. |
v7.0 (2017-01-03) — when the flagship became operator-accessible
The most significant version in the timeline is v7.0, which introduced two hardcoded operator IPs directly into the main plugin file:
define('SITEGUARDING_SERVER_IP1', '185.72.157.169');
define('SITEGUARDING_SERVER_IP2', '185.72.157.170');These are two of the four IPs from the dropped siteguarding_tools.php backdoor's allowlist. They gate eight unauthenticated $_GET['task'] handlers in wp-antivirus-site-protection.php that anyone can hit by querying ?task=<name>&access_key=<key> against any installation:
$_GET['task'] | Auth gate | Capability |
|---|---|---|
cron | access_key only | Trigger scan; results POSTed to siteguarding.com |
upgrade | access_key only | Plugin self-update |
standalone | access_key only | Standalone scan invocation |
status | access_key only | Read scan status |
settings | access_key only | Read plugin settings |
get_malware_files | access_key only | Return list of files flagged as malware in last scan |
view_file | access_key + (REMOTE_ADDR == IP1 OR IP2) | Read ANY file under ABSPATH (echoes full contents + size + md5) |
remove_malware_files | access_key + (REMOTE_ADDR == IP1 OR IP2) | Delete files from disk based on the SiteGuarding-server-stored "last_scan_files" list |
Two of these — view_file and remove_malware_files — are filesystem-level primitives accessible to anyone holding the right access_key from one of the two operator IPs. Effective capability: the SiteGuarding operator can read or delete any file on every wp-antivirus-site-protection install, on demand.
The access_key is per-install, assigned during the "Register your website on SiteGuarding.com" flow — but SiteGuarding's server stores every issued access_key (it IS the license-validation server). So SiteGuarding has perpetual (access_key, IP) combo for every install.
Combined with the consent-based siteguarding_tools.php drop into WordPress root (the flagship's "remote management tool" flow which adds Task_includefile for full RCE), the flagship's effective threat model matches the inline-bundled Tier A plugins — just delivered through a different code path.
Architectural arc
The plugin's 50-version history shows three distinct development phases:
Phase A (2014-05 → 2015-04, 25 versions, v1.2 → v5.0.3) — rapid feature growth from 1,210 to 4,857 LOC. Average release cadence: every ~13 days. SiteGuarding-server phone-home present from v1.2 (day one), but no operator-IP allowlist or view_file/remove_malware_files primitives yet. The SaaS-plugin baseline shape.
Phase B (2015-04 → 2017-01, 17 versions, v5.0 → v7.0) — slower iteration, deeper integrations. Average release cadence: every ~38 days. Login-protection, cron-based scanning, switch to wp_remote_*, rewrites of the scanner class. The plugin's footprint reaches ~9,000 LOC. Phase B ends with v7.0 introducing the IP-allowlisted task handlers.
Phase C (2017-01 → 2018-06, 8 versions, v7.0 → v7.5.4) — operator-access era. The plugin now exposes view_file + remove_malware_files to any caller from 185.72.157.169 or 185.72.157.170 with the install's access_key. v7.5 (May 2017) doubled the codebase to 14,624 LOC, then iteration slowed dramatically. Three minor releases (7.5.1, 7.5.3, 7.5.4) over the next 13 months added a combined 35 lines.
Phase D (2018-06 → 2020-06) — silent abandonment. Zero commits for 24 months. By contrast, during 2014-2018 the plugin shipped one new version every ~30 days on average. The 2018-2020 dormancy represents an effective 10x slowdown to zero. Other portfolio plugins continued to receive updates during this period (@sgdevteam was active through 2019-2020), so the dormancy was specific to the flagship — possibly indicating customer acquisition had moved to direct sales via siteguarding.com or development effort had shifted to the smaller portfolio plugins where the inline-bundled siteguarding_tools.php distribution shape was less likely to attract review.
The flagship sat at v7.5.4 for 2 years before wp.org's 2020 cleanup wave caught it.
Verdict
malicious
IOCs to extract
- kind: domain, value: siteguarding.com, confidence: high
- kind: domain, value: cmsplughub.com, confidence: high
- kind: domain, value: safetybis.com, confidence: high
- kind: url, value: https://www.siteguarding.com/ext/panel_api/index.php, confidence: high
- kind: url, value: https://api.cmsplughub.com/updater.php, confidence: high
- kind: filename, value: siteguarding_tools.php, confidence: high
- kind: code_pattern, value: SITEGUARDING_SERVER, confidence: high
- kind: code_pattern, value: SITEGUARDING_SERVER_IP1, confidence: high
- kind: code_pattern, value: SITEGUARDING_SERVER_IP2, confidence: high
- kind: code_pattern, value: Task_includefile, confidence: high
- kind: code_pattern, value: 185.72.157.169, confidence: high
- kind: code_pattern, value: 198.7.59.167, confidence: high
- kind: code_pattern, value: NS1.SITEGUARDING.COM, confidence: high
- kind: file_hash, value: 36085499a539d4543b1ec0f59f1ad0c7, confidence: high
- kind: file_hash, value: 3eddf6d18214d0d612809efd585a2471, confidence: high