An attacker used a contributor's GitHub account to replace the download archives on five existing releases of OVHcloud's command-line tool on Monday, October 19. The account had been hijacked, and the new files were a build designed to steal secrets stored on the disk of any machine that runs it, the cloud provider says.
They were live on GitHub for up to 94 minutes, from 12:47 to 14:21 UTC, and reached only people who installed or updated the OVHcloud CLI during that window, via a path that checks for no hash, on macOS, Linux x86_64 or arm64, or Windows x86_64.
OVHcloud deleted the swapped archives and published a clean v0.16.0 that evening as an immutable release, whose files GitHub will not let anyone change. The source code, the release tag, and the company's build pipeline were not touched: the bad build was a plain go build of a later commit, uploaded straight onto releases published between April and September.
On v0.15.0, the attacker replaced six files: the macOS x86_64 and arm64 archives, the Linux x86_64 and arm64 archives, the Windows x86_64 archive, and the checksums.txt file, so the published hashes matched the new binaries. The same six files are now gone from v0.11.0 to v0.14.0 as well. The Linux i386, Windows i386, Windows arm64, and WebAssembly builds were left alone on every release.
OVHcloud lists v0.11.0 through v0.15.0 as compromised and v0.10.0 as clean. Those five releases were published between April 14 and September 16, so a copy installed before 12:47 UTC on Monday and not updated since is the original.
You got a swapped file if, in that window and on one of those platforms, you:
Ran the official install script (curl -fsSL | sh). It downloads the latest release archive and installs it, and has never checked a hash.
Downloaded an archive from the GitHub release page of any of the five releases.
Ran a CI job or build step that fetches the archive from the release download URL without a pinned hash.
Ran the CLI's own upgrade command from a v0.12.0, v0.13.0, or v0.14.0 install on a macOS or Linux machine where the tool was installed by the script or by hand. The command downloads the archive and replaces the binary with no hash check. On a Homebrew or go install setup it only prints the command to run instead.
You did not get it if you:
Installed with Homebrew, whose cask in force during the window pinned the original SHA-256 of each archive. Homebrew refuses a download whose hash does not match, so brew install or brew upgrade would have failed rather than installed the swapped file. Some early write-ups listed Homebrew among the exposed paths, but The Hacker News checked the tap's commit history: nothing changed between the v0.15.0 cask on September 16 and the v0.16.0 cask on Monday evening.
Used go install or built from source. The v0.15.0 tag still points at its September commit, 760fd72.
Pulled the Docker image . Its latest tag was last pushed on September 21, four weeks before the swap, and had not been rebuilt as of Tuesday.
Installed before 12:47 UTC on Monday and did not update during the window.
The customer who caught the swap pulled the build information out of the new v0.15.0 Linux arm64 binary with go version -m, which reads the file without running it, and posted it in a GitHub issue . Three things mark the bad build:
The module line reads v0.15.1-0.20261013083505-5ead8ef9b43d+dirty, a pseudo-version, the stand-in string Go generates for a build from an untagged commit, here one from October 13. A genuine release carries its tag number: OVHcloud's clean v0.16.0 build reads v0.16.0+dirty.
The recorded commit is 5ead8ef, not 760fd72, the commit the v0.15.0 tag points to.
A -ldflags="-s -w" line is present. OVHcloud's release pipeline builds with a version flag that Go leaves out of the recorded flags, so a genuine release shows no -ldflags line at all.
Advice circulating that any build marked +dirty, or carrying vcs lines, is the malicious one would flag OVHcloud's own release. The Hacker News ran the same command on the clean v0.16.0 Linux x86_64 binary: it reports v0.16.0+dirty, vcs.modified=true and the commit it was built from.
The only published hash of a swapped file is the v0.15.0 Linux arm64 archive:
SHA-256 (swapped archive): 3833daffcaaaab27e4e0e0833240ffcb1df8df648f4ec0bc4a75c176e28933cb
SHA-256 (original archive): 5c2beb56e6d83a4b426565a1557791ef759316abcc4effb38dd627c90aeb80e0
A build without the version flag would report its version as undefined, but running a suspect binary to find out is not advisable.
OVHcloud founder Octave Klaba wrote on X on Monday evening that anyone affected should change every secret stored on the disk. =
The CLI keeps OVHcloud API credentials in ~/.ovh.conf and reads them from environment variables, according to its documentation , and the advice covers everything else on the disk, not only those files.
If you ran a swapped build, or cannot tell, treat every secret readable from that machine as exposed and rotate it. OpenSourceMalware, which investigated the incident, adds: do it from a different machine.
Remove the binary and install v0.16.0 . The release is immutable and carries a release attestation, a signed record of its files. Updating replaces the program but does not revoke a key that was already copied, which is why the rotation comes first.
Check a downloaded archive against the release with gh release verify-asset v0.16.0 FILE, as GitHub documents .
OVHcloud has not said which files the binary reads, where it sends them, or how many copies were downloaded, and no copy of a swapped archive has been analyzed in public. The company has promised a detailed postmortem in the coming days.
Anyone with write access to a GitHub repository can delete the files attached to a release and upload new ones with the same names, and the download URL does not change unless release immutability is enabled.
The setting, generally available since October 2025 , locks a release's files and tag but protects only releases created after it is enabled.
OVHcloud had not enabled it. In a second post on Monday night, quoted by , Klaba wrote that the problem stemmed from the immutability option not being activated, so a user with the right permissions could modify existing releases directly on GitHub without any checks by the company's CI/CD pipeline. The option has now been enabled, and the pipelines themselves were not affected.
The five old releases now offer only the four archives the attacker did not touch.
The uploads came through the account of a contributor whose merged work is in OVHcloud's documentation repository and who is not a public member of the organization, according to OpenSourceMalware , which built a timeline from GitHub's server-side records.
The release workflow never ran: the run list shows no workflow between October 16 and the v0.16.0 tag push at 16:00 UTC on Monday. First checks found no other repository affected, Klaba wrote in his first post, and OVHcloud has not said how the account's credentials were taken.
A customer's CI job caught the swap because it pins the SHA-256 of the Linux arm64 archive and began failing. With no private reporting channel on the repository, the customer filed a public issue, at 13:50 UTC by OpenSourceMalware's timeline, and OVHcloud deleted the swapped files half an hour later, at 14:21 UTC (16:21 in Paris). v0.16.0 followed at 17:16 UTC, published under the company's ovh-cds account with a signed tag.
The GlassWorm Question
OpenSourceMalware ties the account to GlassWorm , the malware campaign that hides code in invisible Unicode characters and fetches its stage from the memo field of a Solana wallet's transactions. Four of the account's personal repositories were force-pushed on March 5 and 6 with an amended commit that added a loader of that kind, the researchers found.
The wallet that loader reads is the one named in GlassWorm's ForceMemo campaign , which force-pushed malware into hundreds of Python repositories in March with stolen GitHub tokens. The Hacker News confirmed that the loader file is still in one of those repositories, with the hash the researchers published.
Whether the same actor did both is "our inference," the researchers wrote. The shared account is the link, and nothing from the October binary has been tied to GlassWorm, because no copy of it was preserved.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
