astropod Contact Us sign in

A BGP Hijack Attack led to attackers swapping a valid package for a malicious one

Published on gastropod.io on 09-04-2026

A BGP Hijack Diverted Softaculous Update Traffic and Delivered a Malicious Virtualizor Package


Tags: vulnerability-intelligence, software-supply-chain-security, bgp-hijacking, update-integrity, code-signing, hosting-infrastructure, provenance


At approximately 20:57 UTC on August 28, AS62390 (NexonHost) began announcing 162.55.80.0/24 through transit provider AS6204 (Zet.net). That block belongs to Hetzner and carries IP addresses for Softaculous systems, including the software update endpoint and the client area and billing site. Hetzner normally announces only the surrounding 162.55.0.0/16, so the more specific announcement won standard BGP route selection on every network that accepted it. The hijacker kept AS24940 (Hetzner) at the tail of the AS path, so Hetzner appeared as the origin in every routing snapshot.

Softaculous confirmed in its incident advisory that the attacker delivered a malicious Virtualizor update package to installations that checked for updates while their traffic was diverted. Virtualizor is the VPS management control panel that hosting providers use to run KVM, Xen, LXC, OpenVZ, and Proxmox nodes, so a poisoned update executes as root on a hypervisor rather than on a single web server.

The attacker also obtained a valid Let's Encrypt certificate for the Softaculous domains, because the certificate authority's automated domain-ownership validation traversed the same hijacked route. Clients and browsers on a diverted path saw no certificate warning. The fraudulent certificate covered 26 names, including virtualizor.com, api.virtualizor.com, and files.virtualizor.com.

Virtualizor reconstructed the incident from RIPE Routing Information Service data at ten-minute resolution. All 368 RIS collector peers carried the hijacked route at some point. While a wave was propagating, roughly 72 percent of the full peer set had a best path through the hijacker, which makes this a globally visible hijack rather than a regional one. The route flapped hard, with about 10,600 withdrawals recorded in the window, and Hetzner's countermeasure announcement produced an eleven-hour gap on August 29 with almost no diversion. A server received the malicious package only if an update check happened during a diverted interval and completed, which is why Softaculous describes the impact as a handful of servers rather than the general user base.

The AlbaHost hosting provider reported on LowEndTalk that 5 of its 34 checked Virtualizor hypervisors carried the same malicious modifications. The attacker inserted commands into three legitimate Virtualizor files, and a root cron job executed the modified code. That code added an attacker-controlled key to the root account, installed Java 17 where the runtime was absent, downloaded a Java payload, and executed it as root. The payload established persistence through a systemd unit at /etc/systemd/system/java-jre-update.service, created an account named proxyuser, and connected to cdn[.]nerat[.]cc and connect[.]ne-rat[.]xyz. AlbaHost recorded a successful password-based SSH login to proxyuser from 193.32.127[.]248.

Two failures made the routing attack pay off. Virtualizor's update clients performed no cryptographic verification of update packages, so TLS and correct routing were the only things standing between an operator and attacker-supplied code. The company released Virtualizor 3.2.9.9 with a Security Analyzer on September 1 and has stated that package signing is still future work. Second, because the attacker's server answered the requests, Softaculous has no logs of them. The company cannot produce a list of affected installations and no affected-version range exists, so every Virtualizor operator has to check every server by hand.

A valid certificate on a hijacked route proves that somebody controlled the name at validation time. It says nothing about what bytes the client received. I made a similar point about npm provenance attestations in the AsyncAPI compromise, which I have already covered here: https://gastropod.io/news/asyncapi-npm-supply-chain-attack-a-valid-signature-isn-t-the-same-as-a-safe-package. Transport authentication and content integrity are separate problems, and hosting operators just paid for treating them as one.

Content-addressed identity is what survives a diverted route. Gastropod resolves every artifact it proxies into a PURL, version, source, and sha256 digest, and verifies each artifact against the authoritative source for its ecosystem before that digest enters your inventory. A substituted package produces a different digest and an identity mismatch, whatever the certificate on the connection looked like. Gastropod also records who did every pull, what they pulled, from where, and when, on your side of the connection rather than the vendor's. Operators reconstructing this incident are working from a vendor that has no logs at all; a per-pull audit record answers "which of my hosts fetched from that endpoint during those 33 hours" as a query instead of a server-by-server inspection. The product page covers how the digest identity and the audit spine work.

Sources

← news