Home/ Blog/ Security news/ Article
Blog · Security news

cPGuard Update Hijack: Root Backdoor Hit 2,950 Servers, Rotate Keys

A hijacked cPGuard update ran as root on about 2,950 servers, stealing SSH keys, MySQL root passwords and hashes. Indicators, checks and what to rotate first.

Dark cover card with the headline cPGuard update hijacked to backdoor 2,950 servers

A server security agent is the one program on a hosting box that is expected to run as root, phone home, and replace itself without asking. That is exactly why the cPGuard compromise matters more than a typical poisoned package. For roughly 70 minutes on November 2, the cPGuard update channel delivered a script that ran as root on about 2,950 customer servers, according to the vendor, OPSSHIELD. It left a hidden root shell behind and bundled up the box's most useful secrets: the shadow file, root's SSH keys, the database superuser password and everything root had typed at the prompt. Updating removes the backdoor. It does not take back anything that already left.

cPGuard is a web server security suite marketed to hosting providers and server operators, with editions for cPanel/WHM, DirectAdmin, Plesk and standalone Linux servers. If you run it anywhere, the question for this week is not only "am I patched" but "which of my secrets now belong to someone else, and where else do they open doors."

What did the cPGuard attacker get, and how did they get in?

OPSSHIELD's incident disclosure traces the entry point to its own billing portal at manage.opsshield.com, not to any customer system. The attacker registered a customer account under a false identity, ordered a trial, and was running commands on the server that handles billing and licensing by late evening on November 1. From there, a stolen access key let them upload a fake update to cPGuard's update storage in the early hours of November 2.

How a trial signup became a root push to customer servers1 Nov 15:38: Portal probing. 1 Nov 16:34: Trial account. 1 Nov 22:58: Billing server RCE. 2 Nov 02:04: Fake update upload. 2 Nov 02:08: Agents install it. 2 Nov 03:20: Push window ends.How a trial signup became a root push to customer servers1 Nov 15:38Portal probing1 Nov 16:34Trial account1 Nov 22:58Billing serverRCE2 Nov 02:04Fake updateupload2 Nov 02:08Agents installit2 Nov 03:20Push window ends
Source: OPSSHIELD incident disclosure, 3 November 2026. All times UTC.

By the vendor's clock, probing of the portal started at 15:38 UTC on November 1, the trial signup followed at 16:34, and the attacker had code running by 22:58. The fake update was uploaded between 02:04 and 02:09 UTC, and agents installed it between 02:08 and 03:20. The vendor has closed two candidate holes in the billing application but is still working out which request the attacker actually used. It says SSH, the control panel, FTP and API tokens were not the route.

One intrusion produced two separate groups of victims, and each needs its own response:

  • About 2,950 customer servers executed the rogue build. On each one it went after /etc/shadow and /etc/passwd, root's SSH keys and authorized_keys, /root/.my.cnf with the MySQL root password, root's shell history, and on some servers the S3 credentials in /root/.s3cfg.

  • About 7,900 billing portal accounts lost names, company names, postal addresses, emails and bcrypt password hashes to the attacker. Card data does not appear anywhere in the disclosure.

The script did not send its loot to an attacker host. It parked the files on OPSSHIELD's licensing server under an account the attacker controlled, and the attacker collected them from there, according to the vendor's first advisory. That detail matters for detection: the stolen data went to the vendor's own infrastructure, not to an attacker-owned host, so an egress rule that trusts the vendor's servers would not have flagged it.

The two OPSSHIELD notices do not fully agree

OPSSHIELD published two notices on November 3, and the details shifted between them. Read both before you decide a server is clean.

  • Fixed version. The first advisory says cPGuard 5.88.25 or later removes the backdoor. The later disclosure says the clean release is 5.88.26, described as the build that removes the hidden root shell. Target the newest build available and confirm with cpgcli --version.

  • Exposure window. The later disclosure frames exposure as servers online between 02:08 and 03:20 UTC. The first advisory lists the bad builds as 5.88.12 to 5.88.19 and shows sample install-log entries for those versions as late as 12:46 UTC that day. Until OPSSHIELD reconciles the two, treat any server whose install log shows a 5.88.12 to 5.88.19 entry as exposed, whatever the timestamp.

  • Scale. The first advisory put the attacker's haul at roughly 32 files pulled back so far, a number it labelled preliminary and not the total of affected servers. The later disclosure gives the 2,950 server figure. BleepingComputer, which reported a spokesperson's figure of 2,946 servers, is consistent with the larger number. Plan for the larger number.

Why a security agent's update channel is the worst one to lose

Most supply-chain stories involve a library that runs with whatever rights the application has. A host security agent is different by design. It needs root to scan files and block traffic, it auto-updates so signatures stay current, and admins are trained to leave it alone. Compromise its updater and you inherit all three properties at once: root, reach, and a process nobody questions.

This is the second time in about two months that a root-running tool from the hosting stack has shipped a malicious update to its own users. In late August, a BGP hijack pushed a poisoned Virtualizor update that ran as root on hypervisor control panels. The mechanism was different (routing there, a breached billing portal here) but the lesson is the same. The update path of server-management software is a trust boundary, and most operators verify it by not thinking about it. It also echoes the poisoned security scanner that walked out of build servers with cloud keys: the tools we install to watch for intruders are attractive precisely because they are already trusted everywhere.

One more trust path deserves attention. OPSSHIELD's support access works by adding a vendor SSH public key to root's authorized_keys. The company shipped a precautionary update on November 3 to remove those keys. It has not said whether the private half of that key was exposed. Whatever the answer, a vendor key that sits in root's authorized_keys permanently is standing access, and this incident is a good moment to decide whether you want it there between support tickets.

Patching closes the hole. Rotation is the actual fix.

The fixed build deletes the backdoor and the staged files. It cannot reverse the theft. The value of what was taken differs by file, so rotate in order of how fast it can be used:

  1. Plaintext first. The database superuser password stored in /root/.my.cnf, S3 keys in /root/.s3cfg, and anything typed into root's shell history (API tokens, DigitalOcean tokens, passwords passed on a command line) need no cracking. Assume they are already in use.

  2. SSH keys next. Replace the private keys under /root/.ssh and remove their public halves from every machine that trusts them. OPSSHIELD's own guidance is to treat servers reachable with those keys as exposed too. On a hosting fleet that is often the backup host, the other nodes, and the jump box, so map the trust before you rotate.

  3. Password hashes last, but do not skip them. /etc/shadow hashes are one-way, but weak or reused passwords fall to offline cracking. Working from a session you trust, set new passwords for root and every local account that has one, then change the same passwords anywhere they were reused.

  4. Portal accounts separately. Every OPSSHIELD billing customer should reset the portal password and turn on two-factor login, even if no server was online during the window.

OPSSHIELD does not recommend a routine rebuild. Its later disclosure does say that a server the attacker accessed manually should be rebuilt from a clean backup taken before November 1. The setuid-root shell the script left is the reason to take that seriously: once a root-level shell has sat on a box, a clean file listing is weak evidence. If you cannot account for what happened on the server between the install and the fix, the rebuild is cheaper than the doubt.

How do I check whether a cPGuard server was hit?

Start with cPGuard's own install log: any "Successfully updated" line naming a build between 5.88.12 and 5.88.19 means the server took an affected update. A missing or truncated log does not clear the server. Then look for the files and the persistence the script left, and search web and firewall logs for the operator address OPSSHIELD published.

cPGuard compromise: checks and published indicators (OPSSHIELD, 3 Nov 2026)
grep 'Successfully updated' /opt/cpguard/logs/install_log
cpgcli --version
/etc/cron.d/i93677
/var/tmp/.i93677/
/var/tmp/.cpg91511_sh
/var/tmp/.cpg91511/
/var/tmp/.cpg91511/loot.tgz
94.183.188.91
User-Agent: cPGuard/5.88.11
2c2acd988da531d133d0e17f245c49bf15781278f837543d18c95e8410eabd38  cpguard-v58812-i91511.sh
ffd7a47f65fa1244429baa936ae94be54676b53d2f88bc39564f24e22011de8a  cpguard-v58812-i91511b.sh
d73919af84bf46de941db85e27fd1abc65701ef9ce6cf33bb27c5397f4a41c26  cpguard-v58812-i91511c.sh
6add0201e9a3d02de772d561d05e0da86eb1c538686753b7adcc3aedf7366f77  cpguard-v58812-i91511d.sh

The fixed build is supposed to remove the cron file and the /var/tmp paths, and OPSSHIELD asks customers to confirm they are gone and delete any that remain. Finding them absent after the update proves nothing about whether the script ran. The useful evidence lives elsewhere: the install log, outbound connections in the window, unfamiliar entries in authorized_keys, and any new setuid binaries. The disclosure also lists a gsocket backdoor and a Go implant with process-hiding tricks, but notes those came from OPSSHIELD's own internal server, not from customer machines. They are worth a search, but they are not the customer-side signature.

The last check is the one most teams forget. Watch for the stolen credentials being used after you rotate: a login with an old SSH key, a database connection from an unexpected source, S3 activity on a retired key. A theft like this tends to show up downstream weeks later, on a system that never ran cPGuard at all.

Topics

Frequently asked questions

Which cPGuard versions were affected by the update compromise?

OPSSHIELD lists cPGuard 5.88.12 through 5.88.19 as the affected updates, pushed on November 2, 2026. Its first advisory says 5.88.25 or later removes the backdoor, while its later disclosure names 5.88.26 as the clean build. Install the newest available version and confirm it with cpgcli --version.

What data did the malicious cPGuard script steal?

The script read /etc/shadow and /etc/passwd, root's SSH keys and authorized_keys, the MySQL root password in /root/.my.cnf, root's shell history, and on some servers S3 keys in /root/.s3cfg. OPSSHIELD says not every file was collected from every server, so assume all of them were taken.

How do I know if my server installed the bad cPGuard update?

Run grep 'Successfully updated' /opt/cpguard/logs/install_log and look for any version from 5.88.12 to 5.88.19. A match means the server took an affected update. A missing or incomplete log does not prove the server is safe, so contact OPSSHIELD Support if you cannot tell.

Is updating cPGuard enough after the compromise?

No. The fixed build removes the backdoor and staged files, but it cannot undo the theft. On any exposed server, reset root and local passwords, replace root SSH keys everywhere they are trusted, and rotate the MySQL root password, S3 keys and any tokens found in shell history.

Were OPSSHIELD billing customers affected even without cPGuard online?

Yes. OPSSHIELD says about 7,900 billing portal accounts had their name, company, postal address, email and bcrypt-hashed password copied. It asks every portal customer to reset the portal password and enable two-factor login, even if no server was online during the update window.

See what Suriq finds on your own servers.

Agentless checks for uptime and your cloud, a lightweight agent for detection on each server, and one console that ranks and explains what it finds.