cPGuard's Own Update Channel Shipped a Root Backdoor to About 2,950 Servers in 70 Minutes. The Way In Was the Billing Portal.

If you run cPGuard on a hosting server, run cpgcli --version now. Versions 5.88.12 through 5.88.19 are the malicious updates, and the fix is 5.88.25 or later. If your install log shows any of those versions, treat the server as compromised: the script took the shadow file, root's SSH keys and shell history, and planted a setuid-root shell.

What happened
OPSSHIELD LLP, the company behind the cPGuard server security product, published two notices on November 3. They say an unidentified attacker got into the systems that distribute cPGuard updates and pushed fake versions 5.88.12 through 5.88.19 on November 2. Servers that checked for updates during the window installed them, and the update ran as root. OPSSHIELD says it detected the attack within 12 hours of the updates going out.
The scale, in OPSSHIELD's own words: about 2,950 customer servers ran the fake update, and the attacker also copied about 7,900 billing accounts (name, company, postal address, email and a bcrypt-hashed password). SecurityWeek puts the window at roughly 70 minutes, which matches the logged install times of 02:08 to 03:20 UTC.
How they got in
The second notice reads like an incident timeline, and it is worth reading in full. All times are UTC.
On November 1 at 15:38 the attacker began probing the billing portal. At 16:34 they registered a customer account under a false identity and ordered a free cPGuard trial. At 21:17 they installed the trial on their own server to study how the licensing agent works. cPGuard flagged and banned them twice, at 21:40 and 21:51. At 22:50 they sent crafted requests to the billing portal's callback pages, and by 22:58 they had command execution on the billing and licensing server.
Then, on November 2 at 02:04 to 02:09, they uploaded a fake update to the update storage using a stolen access key. The agents on customer servers started installing it at 02:08. At 02:13 the attacker copied three of OPSSHIELD's cloud servers.
OPSSHIELD says its logs do not record the exact request that gave the attacker access, and that it is still investigating how the credentials were obtained. The two notices also differ on small details: one calls the compromised system the update distribution infrastructure (CDN) and the other calls it update storage.
What the script took and left
OPSSHIELD describes the script as a short collector, not a long-term implant. It gathered the password and shadow files, everything under root's SSH directory, the MySQL root password file where one existed, root's shell history, and cloud storage keys on a small number of servers. It staged the loot in a hidden directory, uploaded it to OPSSHIELD's licensing server through a compromised account, and left a setuid-root shell at /var/tmp/.cpg91511_sh, plus a scheduled task at /etc/cron.d/i93677.
The first notice says OPSSHIELD has found nothing beyond the collection and that backdoor so far, and calls the finding preliminary. Separately, the second notice reports two further backdoors on OPSSHIELD's own internal server, a gsocket one and Go implant copies. Those are on their infrastructure, not on customer servers.
One thing to check on your side: cPGuard has a support-access feature that adds an OPSSHIELD SSH public key to root's authorized_keys. OPSSHIELD says it is releasing an update that removes those keys. The Hacker News reports that OPSSHIELD has not said whether the matching private key was exposed. Look at your authorized_keys file either way.
What to do
Update every server with cpgcli update --start, then confirm with cpgcli --version. Here the two OPSSHIELD notices disagree: the first names 5.88.25 or later as the fixed version and the second names 5.88.26 as the published clean update. Use 5.88.26 if you can get it, and 5.88.25 or later otherwise.
Then search the install log at /opt/cpguard/logs/install_log for the phrase Successfully updated. Any line showing a version from 5.88.12 to 5.88.19 means the server may have run the script. A missing or incomplete log does not prove a server is clean.
If the script ran or may have run, work from a trusted recovery environment and do these in order:
- Reset the root password and every local account that has a password, and change any of those passwords that you reused elsewhere, from a device you trust.
- Rotate database passwords, S3 keys, DigitalOcean tokens, and any secret that appears in root's shell history.
- Replace the SSH keys under /root/.ssh, and remove the old public keys from every system that trusted them. Treat any server this one could reach with an SSH key as exposed until its keys are replaced.
- Look for /var/tmp/.cpg91511_sh, /var/tmp/.cpg91511, /etc/cron.d/i93677 and /var/tmp/.i93677, and review authorized_keys for keys you do not recognize.
- Reset your manage.opsshield.com password and turn on two-factor login.
OPSSHIELD does not recommend a full server rebuild as a routine response. It says to rebuild if you cannot establish the server's integrity, and to rebuild from a clean backup taken before November 1 if OPSSHIELD told you the attacker logged in to your server by hand.
What we checked, and what we hold
OPSSHIELD published one attacker address, 94.183.188.91, described as the main operator address. We ran it through our edge instruments since October 5: 43,467 edge block records, 24,013 canary records and 1,229 origin honeypot records, with zero matches in each. That is a measurement against a non-empty window, and it says only that this address did not touch our edge. We are not claiming we saw this early; we read OPSSHIELD's notice like everyone else.
We ingested what OPSSHIELD published: the attacker address and the SHA-256 hashes of the four script variants (cpguard-v58812-i91511.sh, and the b, c and d variants), all credited to OPSSHIELD as the source. They are in the feed under the source label manual-batch-cpguard-opsshield-2026-11. We did not ingest the file paths, because paths are not feed indicators, and we did not ingest any OPSSHIELD domain, because the billing portal is the victim here.
Limits
We read the two OPSSHIELD notices, The Hacker News and SecurityWeek. We did not reproduce anything, and we did not see a sample. No CVE was assigned in any source, no outside discoverer was named, and no hashes were given for the backdoor shell or the implant binaries. The 32 collected files OPSSHIELD mentions are its own preliminary estimate. All counts are OPSSHIELD's.
Five percent of this is wrong somewhere. It always is. The numbers will move again before you finish reading.
Was this useful? Rate this post. The widget is at the bottom of the page, and we read every response.
Every indicator in this post is in the feed. Free.
1.58M+ IOCs, STIX 2.1 / TAXII, 88% novel vs ThreatFox, exploited-CVE leads ahead of CISA. No credit card — a free API key in 30 seconds, and you can audit every claim above against the live endpoints.