Skip to content
HN On Hacker News ↗

From a 7 KB file to a 13-year backdoor operation

▲ 17 points 5 comments by ValentineC 5d ago HN discussion ↗

Pangram verdict · v3.3

We believe that this document is primarily AI-generated with some human-written content

83 %

AI likelihood · overall

AI
14% human-written 86% AI-generated
SEGMENTS · HUMAN 0 of 5
SEGMENTS · AI 5 of 5
WORD COUNT 1,597
PEAK AI % 99% · §1
Analyzed
Jun 19
backend: pangram/v3.3
Segments scanned
5 windows
avg 319 words each
Distribution
14 / 86%
human / AI fraction
Verdict
AI
Pangram v3.3

Article text · 1,597 words · 5 segments analyzed

Human AI-generated
§1 AI · 99%

Most plugin closures are uneventful. A developer stops responding, wp.org pulls the plugin, the listing goes dark, and that is the end of it. My WP Beacon scanner flags these all day long. I glance at them and move on.

One of them recently was different. The wp.org Plugin Review Team had not just closed a plugin called wp-advanced-math-captcha. They had reached into it and deleted a single 7 KB binary file. A .dat file. Routine closures typically do not touch random binaries. So I decoded it.

That one decision pulled a thread that did not stop unraveling. It led to a second plugin, then a brand I had never heard of, then one DNS lookup that tied everything together, and finally to a back catalog of 27 plugins going all the way back to 2013. Then, weeks later, when I stopped waiting for lucky signals and went looking on purpose, it led to six more burner plugins. Then nine more after that. What looked like a handful of unrelated anonymous developers turned out to be a single operator running the same infrastructure across nineteen accounts for thirteen years. Here is the whole thing, start to finish.

7 KBFile that started it

44Plugins under their control

13 yrsOperating in plain sight

19wp.org accounts, one operator

It started with a file that should not have been there.

When the review team commits to a closed plugin, it is a signal. The account plugin-master only shows up when wp.org has triaged something as an actual incident, not just an unmaintained listing. So when the cleanup commit on wp-advanced-math-captcha specifically removed a file called wp-math-captcha.dat, that got my attention. Captcha plugins do not ship compressed binaries.

The file was zlib compressed. Decoding it took one line.

python3 -c "import zlib; print(zlib.decompress(open('wp-math-captcha.dat','rb').read()).decode())"

Out came PHP. A dropper. And right at the top of it, a comment block that told me exactly what I was looking at.

/** * SiteGuarding tools installer for customer's panel * https://www.siteguarding.com * Do not distribute or share.

§2 AI · 85%

* * ver.: 1.7 * Date: 20 Mar 2020 */

The dropper carried a base64 copy of a backdoor named siteguarding_tools.php. On install it wrote that backdoor into the WordPress root, posted the site URL to apitest.siteguarding.com to register the new infection, and then deleted itself. A captcha plugin with six thousand active installs had been quietly planting a remote-access tool on every site that ran it.

What the .dat file actually wasNot data. A self-deleting installer. It dropped a 482-line backdoor into the site root, phoned home to register the infection, and erased the evidence of itself. The plugin looked like a math captcha. The .dat was the entire payload, hidden as a compressed binary so a casual reviewer would scroll right past it.

What else did they leave behind?

The review team had deleted the .dat file. They had not deleted everything. Sitting in the same plugin was includes/advert-test-codes.php, untouched, and it hardcoded a target:

define( 'ADVREC_TARGET_PLUGIN', 'image-optimizer-x' );

A captcha plugin had no business naming an image optimizer in its code. This was a forced-install primitive, a way to push a second plugin onto sites running the first. So I went and pulled image-optimizer-x from the SVN trunk to read it.

The sibling pointed at a brand I had never heard of.

image-optimizer-x was clean when it first launched in 2025. Then on December 16 it grew a 981-line file called CMSPlughubAPI_LicenseValidator.php. It claimed to validate licenses and update a GeoIP database. What it actually contained was two hardcoded RSA private keys and a generic file-downloader, all pointed at a domain called api.cmsplughub.com.

Embedding RSA private keys in a free WordPress plugin makes no sense for licensing. Private keys are for signing and decrypting, not checking a license. These were there for one reason: authenticated, two-way control of the host. But cmsplughub.com was a brand I had never seen, with no obvious connection to the captcha plugin or to SiteGuarding. On the surface these were two unrelated indie plugins from two different developers.

§3 AI · 87%

One DNS lookup closed the case.

Before reading 981 lines of obfuscated validator code, I did the cheap check first. I looked up where cmsplughub.com lived.

Austincmsplughub.com keeps showing up in this image plugin. Run whois and check the nameservers. Is it connected to siteguarding at all, or am I chasing a coincidence?

ClaudeNot a coincidence. Same operator. dig NS cmsplughub.com returns ns1.siteguarding.com and ns2.siteguarding.com. Both cmsplughub.com and siteguarding.com resolve to 198.7.59.167, and the reverse DNS on that IP is server2.siteguarding.com. cmsplughub.com was registered 2025-02-11 as a fresh brand, but it is sitting on SiteGuarding’s own nameservers and the same server.

That was the moment it stopped being two indie plugins. A brand new domain, dressed up as an unrelated company, was running on the exact same nameservers and the exact same IP address as SiteGuarding, on a host literally named server2.siteguarding.com. The DNS lookup was the load-bearing pivot. Without it, the burner plugins looked like two strangers.

Do the cheap check firstI almost dove straight into deobfuscating a thousand lines of validator code. A thirty second dig answered the only question that mattered. When two things claim to be unrelated, check where they actually live before you check what they say.

The author had a back catalog.

SiteGuarding was not a new name to wp.org. It was an old one. The captcha plugin belonged to an anonymous account called @lulub5592, the image optimizer to one called @dalielsam, both with no bio and no website. But the dropper I had decoded named siteguarding.com directly, so I went looking for the original. There was an account, @siteguarding, registered back in 2013. I pulled its full plugin list out of the Beacon database.

SELECT slug, closed_date, active_installs FROM wp_beacon_plugins WHERE author_slug = 'siteguarding';

-- 27 rows. Every one closed in a single 2020 sweep.

§4 AI · 98%

Twenty-seven plugins, published between 2013 and 2020, every single one closed by wp.org between May 4 and June 5 of 2020 for guideline violations. The plugin closures had been silent and nobody connected them. So I built local git repositories for all 27 and grepped them for the backdoor I had pulled out of the .dat file.

Fifteen of them shipped the identical siteguarding_tools.php backdoor inline, byte for byte, same MD5 hash. The rest phoned home a quieter way. Two clean tiers.

The full siteguarding_tools.php backdoor lived directly in the plugin source, identical across all fifteen (MD5 3eddf6d18214d0d612809efd585a2471). Among them: wp-admin-graphic-password, wp-admin-protection, wp-badbot-protection, wp-geo-website-protection, website-blacklist-monitor, and toxic-links-scanner. Install a “security” plugin, get a remote-access tool.

No inline backdoor, but every one reached out to siteguarding.com on its own schedule, ready to be upgraded into something worse. This tier held the flagship, wp-antivirus-site-protection, with 4,000+ installs, roughly 85 percent of the entire portfolio’s user base. An antivirus plugin that phoned home from day one in 2014.

Three accounts, one operator.

The whole point of using separate anonymous accounts is that nobody connects them. On the surface, @siteguarding from 2013, @lulub5592 from 2020, and @dalielsam also from 2020 are three different people. The links between them turned out to be airtight.

The captcha plugin’s .dat dropper plants the exact same backdoor, same MD5, that 15 of the original 2013 portfolio plugins ship inline. That ties @lulub5592 to @siteguarding.

The captcha plugin hardcodes image-optimizer-x as its forced-install target. That ties @lulub5592 to @dalielsam.

§5 AI · 95%

The image optimizer’s cmsplughub.com runs on SiteGuarding’s own nameservers and IP. That ties @dalielsam back to @siteguarding.

And the two burner accounts were closed by wp.org on the same day, April 7, 2026, after staging a coordinated rollout exactly 30 days apart the previous winter.

The triangle closes on itself. Three accounts, one operator, one set of servers, thirteen years apart. That is where the investigation sat for a few weeks. Then a question started bothering me.

If there were two burners, how many were there?

The captcha plugin only surfaced because I happened to glance at one cleanup commit and decided to decode one file. That is not a detection strategy. That is luck. If a single lucky glance found two live burner plugins, the honest assumption was that there were more I had simply never looked at. So I turned the lucky signal into two systematic sweeps across every closed plugin in the Beacon mirror. Both of them came back pointing at SiteGuarding.

AustinThe two burners both surfaced from a Plugin Review Team cleanup commit. Generalize that. Query every closed plugin in the mirror whose final commit was authored by a wp.org review-team account, and separately decode every non-PHP data file in the closed corpus and match it against the SiteGuarding IOCs. I want to know if there are more of these.

ClaudeBoth sweeps hit, and they split into two buckets. One set is burners wp.org force-fixed at closure. The other set hid the payload under non-PHP extensions, so the old grep walked right past them. Six new burner plugins in total, every one pointing back at SiteGuarding. Two burners is now eight.

Sweep A. Which closed plugins did wp.org bother to fix?

A normal closure just hides the listing. But sometimes the review team force-pushes a code change at the moment of closure. They reach in and strip the payload, or ship a remediation release. They only do that when they have already confirmed malware. It is confirmation-grade. So instead of waiting for one cleanup commit to float past, I queried every closed plugin whose final commit was authored by a Plugin Review Team account. Three of the real hits were undocumented SiteGuarding burners: speedup-optimization, wp-plugin-management, and bytedefense.