ovh

Activity

Stars and mentions · Last 30 days, Oct 5 – Nov 3

GitHub stars36
Mentions36
0481216Oct 5Oct 19Nov 3
UTC days · repositories ovh owns4 repositories

Top repositories

ovh’s repositories ranked by new stars, as on trending.

Loading

Contributes to

Repositories outside ovh’s account where ovh opened or reviewed pull requests in the past 365 days.

Who noticed ovh

Everyone who starred or forked ovh’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

36posts
Nov 40 posts
  1. Five releases of OVHcloud's command-line tool were swapped for builds with a credential stealer. A customer caught it: their build had pinned the exact fingerprint, and started failing when it changed. Most builds fail for no reason. This one had one. github.com/ovh/ovhcloud-cli/security/advisories/G…

  2. Reddit · · r/hermesagent · u/Jonathan_Rivera · ovh/ovhcloud-cli

    PSA: Two incidents this week targeted AI agent credentials. If you run Hermes on Railway or installed the OVHcloud CLI, read this. If your Hermes lives on Railway, rotate your keys today. If you installed the OVHcloud CLI on Oct 19, check whether you got the trojaned build. Neither incident is a Hermes vulnerability. Both are worth your attention because the attackers went after exactly what our setups hold: AI provider keys, bot tokens, and agent session history. --- 1. Railway breach (Oct 20–22) What happened - Attackers broke into Railway's build infrastructure, then its CI, and pulled customer environment variables. Some of them were decrypted. - Railway says the attackers were hunting AI provider API keys specifically. - Railway puts the confirmed exposure at up to ~1.85% of workspaces (~100k). It says the riskiest targets were workspaces with lots of env vars or lots of AI keys. - Railway proactively asked Anthropic, OpenAI, OpenRouter, GitHub, Stripe and others to revoke keys. For some vendors it sent every key on the platform. What this means if Hermes runs on Railway Your model keys and bot tokens almost certainly live in Railway env vars. Railway's guidance is that everyone who signed up before Oct 21 should rotate. Do this: - Rotate every model provider key stored there (Anthropic, OpenAI, OpenRouter, Nous, DeepSeek, whatever you use). Revoke the old key; don't just add a new one. - Rotate bot tokens: - Telegram: BotFather → /revoke - Discord: Developer Portal → Reset Token - Slack: regenerate the app tokens - Rotate everything else in those env vars: Composio/MCP keys, database URLs, GitHub tokens. - Redeploy so the new values take effect. - Check usage and billing on each provider for spikes between Oct 20 and 22. If your agent suddenly started throwing auth errors this week: a vendor may have revoked your key as a precaution. That alone doesn't mean your key leaked. Rotate anyway. 2. OVHcloud CLI malware (Oct 19) This is not about renting an OVH server. Your VPS is fine. It's about the ovhcloud-cli tool. What happened - An OVHcloud developer's GitHub account was compromised months earlier through a malicious VS Code extension. - On Oct 19, the attacker used it to swap the release binaries for v0.11.0 through v0.15.0 with a stealer. - The bad files were live for about 93 minutes (14:47–16:21 CEST), with ~250 downloads. - Source code and the build pipeline were not affected. What it stole The list explicitly includes Hermes sessions and history. It also takes: - Claude's config directory, Cursor, VS Code, Continue, Cody and OpenCode databases - AWS, GCP, Azure and DigitalOcean credentials - SSH keys, plus Docker, Kubernetes, npm and Terraform configs, .netrc and git config Check if you're affected. Don't run the binary to check its version. Linux: ls -d /tmp/envchecker-* 2>/dev/null macOS: ls -d "$TMPDIR"envchecker-* 2>/dev/null The stealer leaves an envchecker-<digits> folder behind and never cleans it up. If that comes back empty and you didn't install the CLI on Oct 19, you're almost certainly fine. To be sure, compare the binary's hash with the list in OVHcloud's advisory: md5sum "$(which ovhcloud)" # Linux md5 "$(which ovhcloud)" # macOS If you're affected: - Stop using that machine for anything sensitive. Rebuilding it is the safe call. - Rotate everything on it: SSH keys, cloud credentials, every model provider key, bot tokens, git tokens. - Read through your Hermes session history. Anything you ever pasted into a chat (keys, passwords, client data) should be treated as stolen. People forget this one. - Install v0.16.0 or later. Why this matters Two unrelated attacks in the same week went after agent credentials and agent data by name. That's the trend, and it's going to continue. Cheap insurance that would have limited the damage in both cases: - Set spend caps on every model provider key. - Use one key per deployment. A leaked VPS key shouldn't also unlock your laptop agent. - Keep secrets out of chat. Session logs are being treated as loot now. - Be picky about extensions and CLIs on machines that hold your agent's credentials. The OVHcloud attack started with a color-picker extension. If you were hit by either one, drop a comment, even if it's just "rotated, no unusual usage." That helps everyone gauge how far this actually reached. Sources - Railway preliminary report: blog.railway.com - Railway status/incident: status.railway.com - OVHcloud CLI advisory (hashes + IOCs): github.com/ovh/ovhcloud-cli/security/advisories/G…

    18 points · 12 comments
  3. Reddit · · r/PCAstucesTech · u/Extreme_Host3037 · ovh/ovhcloud-cli

    OVHcloud : une attaque sur son compte Github expose ses utilisateurs à un malware Bonjour preview.redd.it Pendant un peu plus d'une heure lundi, le répertoire permettant de télécharger l'outil de contrôle en ligne de commande d'OVHcloud a été compromis pour diffuser un logiciel malveillant. L'attaque a été repérée par un utilisateur et bloquée par OVHcloud.  OVHcloud a fait face lundi à une attaque très particulière visant son écosystème de développeurs. Dans la journée, un utilisateur a repéré une modification dans les versions de l'interface en ligne de commande (CLI) proposée par OVHcloud et s'en est alerté. Le fondateur d'OVHcloud Octave Klaba l'a confirmé par la suite dans des messages sur les réseaux sociaux. Cette modification n'était pas le fait de ses équipes et visait à diffuser un logiciel malveillant. Il est décrit par le fondateur comme "un binaire dont le job est récupérer les secrets sur le disque." Mise à jour silencieuse L'outil concerné est une interface en ligne de commande permettant d'interagir et de manipuler les produits, comptes et services proposés par OVHcloud. Celle-ci est mise à disposition des utilisateurs via le compte Github officiel de l'entreprise. La compromission a initialement été signalée par un utilisateur sur le compte Github. Il a constaté lundi matin que plusieurs versions du logiciel avaient été mises à jour, sans explication. Ce dernier a donc interpellé l'entreprise sur Github. Selon Octave Klaba, la compromission a eu lieu entre 14h47 et 16h21 avant d'être détectée et bloquée par les équipes de la société. Les versions concernées sont les versions v0.11.0 v0.12.0 v0.13.0 v0.14.0 v0.15.0 : le fondateur assure que les versions v0.10.0 et la version 0.16.0, publiée après l'incident, sont authentiques. Selon les premières analyses d'OVHcloud, l'attaque aurait été rendue possible au travers de la compromission initiale du compte Github d'un des développeurs. En outre, les équipes d'OVHcloud ont découvert quel'option d'immuabilité des versions sur Github n'avait pas été activée sur le projet. Cette option permet de garantir que les fichiers diffusés au moment d'une publication ne peuvent pas être modifiés à l'avenir. En exploitant ce compte compromis et ce défaut de configuration, les attaquants ont pu modifier les exécutables diffusés sans que ceux-ci ne soient détectés par les vérifications habituelles mises en œuvre par OVHcloud. La piste de Glassworm Reste la question de l'auteur de l'attaque et de ses intentions exactes. Octave Klaba n'a pas donné beaucoup de détails sur le logiciel malveillant impliqué dans l'attaque, ni sur ses objectifs. Le logiciel destiné à "récupérer des secrets sur le disque" s'apparente à première vue à un infostealer, mais aucun détail sur l'appartenance à une famille connue de ces logiciels n'a été publié. Il faudra s'en tenir à la description donnée par Klaba, qui qualifie le logiciel comme étant "de qualité médiocre" mais pouvant "aller jusqu'au bout." La société a promis de publier un compte rendu plus détaillé de l'attaque dans les jours à venir. Mais la société spécialisée dans la sécurité de l'open source OpenSourceMalware voit dans l'attaque des liens avec le mode opératoire Glassworm. Glassworm a initialement été identifié en octobre 2025. Ce logiciel malveillant se diffusait à l'origine sous la forme d'extensions OpenVSX compromises, destinées à des environnement de développement, et cherchait à voler des identifiants sur les machines infectées. Ce mode opératoire a ensuite été identifié dans d'autres campagnes visant des développeurs. En fin d'année 2025, le logiciel malveillant était impliqué dans une campagne, baptisée ForceMemo, visant des comptes Github de développeurs. Des indices, mais pas encore de preuve opensourcemalware.com, qui a analysé l'attaque, estime que le compte utilisé pour modifier les exécutables était compromis depuis plusieurs mois. Selon leur analyse, le compte a été utilisé au mois de mars pour diffuser un logiciel malveillant utilisant un wallet Solana comme centre de commande et de contrôle. Ce wallet avait précédemment été identifié dans le cadre de campagnes menées associées à Glassworm. Les analystes s'appuient donc entre autres sur l'utilisation de ce compte Github compromis dans les deux incidents pour attribuer l'attaque à Glassworm. Mais les identifiants de comptes dérobés se monnayent et se revendent fréquemment. L'attaque ayant visé OVHcloud présente néanmoins des similitudes dans son déroulement avec la campagne ForceMemo, attribuée aux acteurs malveillants derrière Glassworm, souligne la société. Il faudra donc attendre l'analyse d'OVHcloud pour avoir le fin mot de l'histoire.

    1 point
  4. OVHcloud's CLI Release Tags Didn't Change. The Files Under Them Did. Release tags do not, by themselves, prove the integrity of the bytes distributed alongside them, and the OVHcloud CLI incident of 19 October 2026 shows how large that gap can be. According to OVHcloud's security advisory (GHSA-862f-55f5-vmvw), published 20 October, the binaries attached to releases v0.11.0 through v0.15.0 were replaced with malicious ones after those releases had been built and published. The release tags stayed where they were. The files under them did not. The decision this post is meant to support is narrow: if a pipeline, a laptop or a golden image pulled a tool from a release page, can anyone say afterward which bytes it ran, and against what independently held evidence? Every claim below is attributed to its source. Where the source is the vendor's own account, I say so, and I do not treat it as an independent forensic finding. !release tags — a v0.14.0 tag label unchanged above two release binaries with different digests What OVHcloud Says Happened The advisory scopes the exposure by version and by time. It names v0.11.0 through v0.15.0 as affected, and only for builds downloaded or installed in a window on 19 October 2026, 14:47 to 16:21 UTC+2. It describes v0.10.0 and earlier, v0.16.0 and later, and anything fetched before the window as unaffected. Its key figures put the period of malware availability at 1h33. Those are the vendor's numbers. The advisory's publication date is 20 October; the material I reviewed does not state a time of publication. OVHcloud attributes the incident to a compromised developer GitHub account. Its advisory traces the compromise to a malicious browser extension installed on the developer's personal MacBook in October 2025, and says stolen keys were later used to replace the release binaries. OVHcloud says the substitutions were not performed from that personal MacBook. It also says the repository "was not appropriately configured to ensure release immutability." This is the vendor's account, not an independent forensic finding. This is a cloud strategy architecture problem before it is a tooling problem. A CLI is a dependency your estate acquires at a point in time from a location that can change underneath you. The download step often encodes a version choice without recording an independently verified expected digest. The shape is familiar from vendor-side compromises that never touch your own perimeter: the vendor's boundary failed, and the authority it held, here the authority to publish bytes you chose to run, did exactly what it was configured to do. Release Tags Held. A Retained Digest Is What Noticed. Issue #300 on the project's repository is the detection record, and it comes from a reporter, not the vendor. The reporter's CI job had kept a SHA-256 for the Linux arm64 binary from an earlier download. A later download of the same release no longer matched it. The reporter also describes build metadata in the new binary that differed from the original, including a +dirty marker. The reporter describes the replacements as occurring over roughly 25 minutes; that observation has not been reconciled with the vendor's incident window. !Layer diagram: source commit, tag and Go module proxy consistent, release asset diverged What that establishes is specific. One downstream job, holding a digest it had recorded itself, saw a mismatch. The reporter's evidence showed that the downloaded binary's digest had changed and its build metadata identified a later, dirty commit. Meanwhile, the v0.15.0 tag and the Go module proxy still pointed to the original commit. The reporter concluded that the replacement binary had not come from the release pipeline. A Git tag identifies a source revision; a release may also publish downloadable assets whose integrity must be established separately. In this repository, by the vendor's own account, those assets could be replaced after publication. What it does not establish is equally specific. It does not show that every check in OVHcloud's build chain passed, and it says nothing about the complete integrity of that chain. Whether the replacement files were built from the same source, or at all from the same pipeline, is not something issue #300 or the advisory lets me assert. The evidence supports one conclusion: the release tags and the content beneath them diverged. In this case, a downstream job noticed because it had kept its own record. The Checksum Sat on the Same Path as the Binary The reporter's check worked because the expected digest had been retained separately from the later download. The issue does not document the exact storage or access controls protecting that record. Reporting on the incident indicates that checksums.txt was replaced through the same release authority as the binaries. If so, a job that downloaded the binary and the checksum file together and compared them would have passed. The comparison would have been honest arithmetic over two attacker-influenced inputs. !Two verification paths: checksum file on the same release path as the binary versus a digest held outside it This is not a new mechanism. It is an instance of the principle already laid out in Your Logs Are Not Evidence If The Infrastructure That Produces Them Can Rewrite The Record: evidence stops being evidence when it depends on the system whose behavior it is meant to vouch for. A checksum served beside the binary shares a publisher, a credential and an upload path with the thing it vouches for. Whoever can rewrite one can rewrite both. The useful question is how the expected digest became trusted. A digest retained outside the release path can detect later changes, as the reporter's CI job demonstrated. It does not establish that the first acquisition was authentic unless that acquisition was independently validated. An internal mirror helps preserve the bytes and their history, but it becomes an integrity control only when the artifact is checked against trusted evidence at ingestion and subsequent use is checked against that record. A checksum fetched from the same release page as the release tags and assets is not that evidence. This also changes how you think about the build job itself. As argued in Your CI-CD Pipeline Is Your Real Infrastructure Control Plane, the job that fetches a tool holds credentials and reach, and the tool it fetches inherits all of it for the duration of the run. Pinning to Release Tags Pins a Label Most install steps in the wild name a version and trust it. A curl against a release download URL, a pinned version in a setup action, a line in a bootstrap script: each one resolves a tag to a file at the moment it runs. Pinning to release tags feels like immutability because the string never changes. It is a pin on the label, and the label is resolved to bytes every time the step executes. Which object you trusted depends on the acquisition path. A fetch of the prebuilt release asset trusts the uploaded file. A build from source at a tag trusts the commit the tag points to. A module-proxy install trusts the proxy's record of that commit. The reporter's account is that the tag and the Go module proxy continued to point to the original commit while the assets changed, which is consistent with the source-level objects being intact. It does not tell you that any particular install path in your estate was safe, and I am not calling any path or platform unaffected on the strength of the sources I have: the reports on individual assets and platforms conflict, and I have not been able to reconcile them. The useful move is to be explicit about what each pin refers to. Pinning release tags is fine as a convenience. It is not a control. The control is a digest that was validated when the file was first acquired, compared on every later fetch, and held where the publisher cannot rewrite it. Retention alone gives continuity; validation at ingestion gives identity, and neither supplies the other. Teams that mirror release assets into an internal artifact store have a place to do this, but a mirror that never checked what it ingested preserves a malicious artifact as faithfully as a good one. Teams that fetch straight from the release page at run time have a version number and a hope. A Hash List of Bad Files Is Not Proof of Good Ones The advisory's appendix lists MD5 hashes for the five malicious binaries, one each for Darwin arm64, Darwin x86_64, Linux arm64, Linux x86_64 and Windows x86_64. It lists no known-good hashes. The advisory says v0.16.0 was released with a signed tag. A tag signature and an artifact signature answer different questions: verifying the tag does not, by itself, establish that a separately downloaded binary matches the intended release artifact. I have not independently verified the v0.16.0 assets. !Five listed malicious hashes beside an empty known-good slot per platform The distinction matters operationally. Published indicators let you ask whether a file you hold matches one of the listed malicious files. A match is useful. A non-match tells you nothing about authenticity: a different substituted file would also be a non-match. MD5 is not an appropriate modern basis for adversarial integrity assurance, and the advisory does not provide known-good artifact digests or describe an artifact-signing or provenance mechanism for consumers to validate the binaries independently. Known-bad identification and known-good verification are different capabilities, and an incident notice normally only gives you the first. The vendor's remediation list deserves the same careful reading. OVHcloud reports it deleted the malicious assets, suspended the developer account, reviewed write access and logs, enabled immutable releases and published v0.16.0. It plans to review build and publication pipelines, require signed commits and merges, make release immutability systematic, review organization-linked GitHub accounts and tie release publishing to its central IAM system. Those are controls on who can publish and whether published files can be changed. They narrow the repeat window. None of them, in the advisory I read, gives a consumer a way to verify that a particular binary is the one the publisher intended; it does not commit to signing release artifacts or publishing provenance. Until that exists, the verification evidence you hold has to come from your side. What the Payload Was Reportedly After I have not analyzed the malware and this section is documentary. OVHcloud's advisory names the categories of local data the malware gathered: cloud credentials (AWS including S3, Google Cloud, Azure), container and infrastructure tooling (Docker, Kubernetes, Terraform), package and platform tokens (NPM, DigitalOcean's doctl), .netrc, the global Git configuration, SSH keys, and the local databases and session histories of editors and AI coding assistants. The advisory's exposure guidance is conditional on execution: it says that if you downloaded or updated the CLI in the window and ran it, the secrets on that computer should be considered compromised. A download alone does not establish exposure. (Its affected-builds section speaks of downloads only, and the advisory does not reconcile the two wordings.) It also describes the malware creating a folder named envchecker- followed by 9 to 10 digits in the temporary directory, which it says is never deleted and can show whether a machine was exposed. That is an attributed indicator to look for, not a reason to run a suspect binary. The list above is the exposure test in practical terms. The relevant question for any machine or runner that executed an affected binary in the window is not whether it was "a CLI host" but what the executing process could read. A build runner with a cloud role, a Terraform state backend and a deploy key is a very different answer from a developer laptop with a stale profile, even if both ran the same file. An Acquisition Worksheet for Tools Your Pipelines Fetch Release tags were never going to catch this, so the remediation belongs to acquisition, not to the tool. For every CLI or binary your estate fetches from a release page, record the following at acquisition. Keep the record in a separate trust domain, with access controls that prevent the release-publishing identity from rewriting it. Validate the artifact against trusted evidence before treating its digest as the expected value for later fetches. !Eight-field acquisition record for a fetched binary with the validation-at-ingestion field empty | Field | What to record | Why it matters on 20 October | |---|---|---| | Tool and version | Exact version string, not "latest" | Scopes you against the advisory's v0.11.0 to v0.15.0 range | | Download source | URL or mirror actually used | Separates release-page fetches from internal mirrors and package managers | | Acquisition timestamp | UTC time of the fetch | The vendor's exposure test is time-bounded, so a timestamp decides in or out | | Binary digest | SHA-256 of the file as acquired | The record a later fetch is compared against | | Source of the expected digest | Where the expected value came from: your own validated ingestion, or whatever the publisher served | Distinguishes a digest you recorded from one the publisher served | | Independent validation at ingestion | What trusted evidence the file was checked against when first acquired, or "none" | Retention gives continuity; only validation gives identity, so "none" must be a visible answer | | Execution status | Where and when it ran, with what identity | Turns "we downloaded it" into "it executed here" | | Accessible credential scope | What the runner or user could read, including the secret types the advisory names | Defines what a rotation decision actually covers | This is a dependency inventory with a time axis. The Dependency Architecture stage of the Cloud Architecture learning path is where the underlying discipline lives, and its Dependency Awareness Boundary (#126) is the line below which a tool fetched in a job step typically sits until someone writes it down. If your answer to the worksheet is "the pipeline downloads latest at run time," you cannot answer the advisory's question from records. You can only answer it from memory and log retention. > ↓ Download: OVHcloud CLI Release Tags Carousel > > Ten slides on the tag-versus-asset boundary, checksum independence, known-bad versus known-good hashes, and the eight-field acquisition record. PDF · 10 slides. > > Download the carousel → Architect's Verdict Release tags are labels. In this incident the label held while the content beneath it changed, and by the vendor's own account the repository was configured in a way that allowed it. Treating release tags as a statement about bytes was the assumption that failed, and it fails the same way for any publisher that has not locked releases down. The real problem is where verification evidence comes from. The party that noticed in this case was a downstream job that had recorded its own digest at an earlier acquisition. A checksum fetched from the release, an incident hash list of bad files and a signed tag do not substitute for that, and even a retained digest proves identity only if the first acquisition was validated. Evidence you cannot show was held independently of the publisher is a claim, and claims about what ran in your estate are exactly what an incident review will ask you to prove. Know what you fetched, when, from where, and against what you checked it. If the answer lives only in release tags on the publisher's page, you do not have an answer. --- Originally published at rack2cloud.com

  5. OVHcloud CLI Supply Chain Attack: Release Assets Replaced to Steal Developer Secrets 1. Basic Information - Article Title: ovhcloud-cli security incident - October 19th, 2026 - Publisher: OVHcloud - Publication Date: 2026-10-20 - Original: OVHcloud - Related Sources: GitHub issue #300, BleepingComputer: OVHcloud CLI releases backdoored on GitHub to steal developer secrets - Related Malware & Threat Groups: envchecker stealer, GlassWorm - Related CVEs: None - Related Products: OVHcloud CLI, GitHub Releases, VS Code, Cursor, Claude, OpenCode, AWS CLI, Google Cloud SDK, Azure CLI, Kubernetes, Terraform - Severity: Critical - Severity Basis: A software supply chain compromise in which binaries distributed under legitimate release names contained code designed to collect and exfiltrate credentials and other secrets for AWS, GCP, Azure, Kubernetes, Docker, SSH, Terraform, and AI coding tools. The capabilities are confirmed; successful theft on individual endpoints remains unconfirmed. - Update Reason: Updated to align the primary source, prerequisites, observation scope, confidence statements, and ATT&CK mappings with primary sources and official specifications. This editorial update is distinct from the original source's publication or update timestamp. 2. Overview Using stolen GitHub keys associated with GlassWorm, attackers compromised an OVHcloud developer account and progressively replaced CLI release assets for versions v0.11.0 through v0.15.0 with binaries containing information-stealing malware between 14:47 and 16:21 (UTC+2) on October 19, 2026. Approximately 250 downloads occurred during this window, and executing the tampered binaries targeted cloud, SSH, and developer secrets on the affected devices. 3. Attack Flow 1. Developer Key Theft (October 2025): GitHub authentication keys were stolen via a malicious extension (color-picker-universal 2.8.91) installed on a developer's personal Mac. 2. Official Release Asset Replacement (October 19, 2026): Attackers abused developer privileges and mutable release settings on GitHub Releases to progressively replace release assets for v0.11.0 through v0.15.0 with locally built malicious binaries. 3. Download and Execution by Users: Users downloaded the affected binaries from official GitHub releases and executed them on their devices (execution can occur after the distribution window and still fall within the incident's scope). 4. Secret Collection and Exfiltration: The envchecker component within the binary gathered development environment and cloud secrets into a temporary directory, archived them, retrieved exfiltration destination details via Solana RPC, and uploaded them to an external server. | Phase | Timing / Timeframe | Abused Elements / Targets | Confirmed Behavior / Scope | | --- | --- | --- | --- | | Initial Key Theft | October 2025 | Malicious extension color-picker-universal 2.8.91 on developer's personal Mac | Theft of GitHub authentication keys (no compromise of source code or the build chain itself) | | Asset Replacement | October 19, 2026, 14:47–16:21 (UTC+2) | OVHcloud CLI v0.11.0 to v0.15.0 (Darwin / Linux / Windows x86_64, etc.) | Replacement of mutable release assets with malicious binaries (~250 downloads) | | Collection & Exfiltration | Upon execution of tampered binary | Temporary directory envchecker-[0-9]{9,10}, Solana RPC, 45.32.148[.]174:443 | Archiving and external exfiltration of cloud, SSH, and AI tool secrets (actual number of victims unannounced) | 4. Attacker Position and Execution Location - GlassWorm-associated threat actors holding stolen GitHub developer keys - Developer account with permissions to modify release assets in the OVHcloud repository - External exfiltration infrastructure (45.32.148[.]174, etc.) receiving secret archives from infected devices 5. Victim and Administrator Perspective Victims - While the CLI appears to function like a standard management tool, secrets are collected in the background upon execution. - On affected devices, simply deleting the binary is insufficient; cascading credential rotation across cloud, source code management, cluster, and SSH accounts is required. Administrators and SOCs - Inference: Review available GitHub audit logs for release asset deletion and re-upload history, and check for the creation of envchecker-* directories combined with external network traffic logs on endpoints. Because this depends on log collection settings and retention periods, the absence of records cannot be treated as proof of no compromise. - On the cloud side, identical credentials leaked from endpoints may appear as subsequent usage originating from unknown sources. 6. Success and Failure Conditions Success Conditions - Downloading a tampered release asset during the affected window (October 19, 2026, 14:47–16:21 UTC+2) and executing the binary (this applies even if execution occurs after the distribution window). - Readable developer and cloud secrets existing on the execution device. - Outbound network traffic (egress) permitted from the device to Solana RPC endpoints and external exfiltration destination IPs. Failure Conditions and Mitigations - Do not execute suspicious binaries; verify them against the malicious hashes and temporary envchecker directories listed in the official advisory, then delete them and switch to clean version v0.16.0 or later. However, replacing the binary alone does not remediate already leaked credentials or existing subsequent compromises. - Revoke and reissue (rotate) all target secrets that existed on the device and investigate audit logs on each cloud service provider's side. - Inference: Maintainers should implement release immutability and provenance verification (such as signatures), while users should verify checksums and attestations using independent and trusted standards. Signed tags alone do not guarantee the contents of mutable release assets. 7. What Happens Upon Success - Theft of cloud and developer secrets for AWS, GCP, Azure, Kubernetes, Docker, SSH, and Terraform, as well as AI coding tool session data and histories. - Abuse of official release channel trust and potential secondary compromise of downstream environments using stolen credentials (subsequent abuse of individual credentials remains unconfirmed at this time). - Although approximately 250 downloads occurred during the affected window, the number of successful executions and successful external exfiltrations has not been publicly disclosed. 8. Observable Logs Inference: The following items are candidates for internal investigation. Availability depends on products, permissions, logging configurations, and retention periods, and individual suspicious operations or missing logs do not conclusively prove attribution or compromise. Email - Check for security notifications from OVHcloud and GitHub, as well as unauthorized usage alerts from cloud providers. Proxy / SWG / DNS - Monitor for outbound traffic to Solana RPC endpoints and 45.32.148[.]174:443. Because destinations can be dynamically updated via Solana, the absence of connections to known IPs does not rule out external exfiltration. Endpoint / EDR - Monitor for the creation of temporary directory envchecker-[0-9]{9,10} immediately following execution of the ovhcloud binary, the enumeration of various credential files, and archiving behavior. Identity / IdP - Check for usage of GitHub tokens, cloud API keys, SSH keys, and service accounts originating from unknown sources. SaaS / Cloud - Cross-correlate audit logs across AWS, GCP, Azure, Kubernetes, and GitHub from October 19, 2026, onward. Network - Check for outbound traffic originating from the official CLI process toward Solana RPC endpoints or external exfiltration destination IPs. 9. Attack Success Determination - Malicious distribution, collection, and exfiltration capabilities confirmed / Success of theft per endpoint unconfirmed - Basis: Publicly, OVHcloud confirmed the distribution of tampered binaries, approximately 250 downloads, and the sample's collection and exfiltration capabilities. However, the number of endpoints on which execution or exfiltration succeeded, and the number of subsequent misuse cases, have not been disclosed. - Scope: The download count of approximately 250 does not represent the number of successful executions, exfiltrations, or subsequent abuses. 10. Investigation Playbook - Trigger: Identify traces of envchecker-[0-9]{9,10} directory creation immediately following ovhcloud binary execution, credential file enumeration, and archive creation. - Initial Verification: Normalize target assets, accounts, and event times into UTC/JST and preserve related logs. - Endpoint / Server Investigation: Inference: Review available GitHub audit logs to verify release asset deletion and uploads, and cross-reference envchecker-* directories with outbound traffic on endpoints. Due to dependencies on log settings and retention periods, the lack of records does not prove the absence of compromise. - Authentication / Cloud Investigation: Check for unusual origin usage of GitHub tokens, cloud keys, SSH keys, and service accounts. - Subsequent Actions: Track whether secrets for AWS, GCP, Azure, Kubernetes, Docker, SSH, Terraform, AI tool sessions, etc., were stolen and utilized secondarily. - Containment: Do not execute suspicious binaries; cross-reference them against official malicious hashes and temporary envchecker directories for deletion, and replace them with v0.16.0 or later. Because replacement alone does not resolve leaked credentials or existing subsequent compromises, revoke and reissue secrets concurrently. - Determination Categories: Clearly separate stages such as contact (download), execution, authentication success, data collection, and subsequent compromise, avoiding premature assumptions of unconfirmed success. 11. Defense and Detection Ideas - Single Events: Detect the creation of envchecker-[0-9]{9,10}, credential file enumeration, and archive creation immediately following ovhcloud binary execution. - Timeline Correlation: Correlate events chronologically, considering the sequence from the initial GitHub key theft in October 2025 via a malicious extension on a developer's personal Mac -> abuse of developer privileges and mutable releases to replace v0.11.0–0.15.0 assets with malicious binaries -> download and execution by users from official GitHub releases -> collection and archiving of secrets into temporary directories by envchecker, destination lookup via Solana RPC, and archive upload to the external exfiltration destination. Organizations should correlate binary acquisition and execution with file enumeration and outbound traffic. - Threat Hunting: Search for outbound traffic from the official CLI process to Solana RPC endpoints or external exfiltration destination IPs (such as 45.32.148[.]174). - Log Limitations: The approximately 250 downloads do not represent unique endpoint counts or successful thefts. Confirming execution and exfiltration requires evidence from both endpoints and network traffic, and log availability depends on configuration and retention periods. - Priority Mitigations: Do not execute suspicious binaries; cross-reference them against official malicious hashes and temporary envchecker directories for deletion and update to v0.16.0 or later (replacement alone does not resolve leaked credentials or subsequent compromises). Revoke and reissue all target secrets and investigate provider-side logs. Inference: Maintainers should ensure release immutability and signature/provenance verification, while users should verify checksums and attestations using independent, trusted standards (signed tags alone do not guarantee the contents of mutable release assets). 12. Facts, Inference, and Hypothesis Facts - Between 14:47 and 16:21 (UTC+2) on October 19, 2026, release binaries for OVHcloud CLI v0.11.0 to v0.15.0 were replaced, resulting in approximately 250 downloads. - Affected release assets include Darwin and Linux builds and the Windows x86_64 build downloaded during that timeframe. Executing a tampered binary is within scope even after the distribution window; the source code, tags, and build chain were not affected. - The malware creates an envchecker directory in temporary storage and collects AI coding tool databases and histories, AWS, GCP, Azure, Docker, Kubernetes, npm, DigitalOcean, SSH, Terraform, .netrc, and git configuration files. - It retrieves dynamic control information from Solana RPC and uploads collected archives to 45.32.148[.]174. - The root cause was key theft by a malicious extension (color-picker-universal 2.8.91) installed on a developer's personal Mac in October 2025, combined with disabled release immutability on GitHub Releases. - Clean version v0.16.0 was published with signed tags and immutable releases enabled. Inference - Even if source code and Git tags are legitimate, mutable release assets can be replaced later, requiring independent verification of checksums, attestations, and immutable releases. - Because the collected items span multiple categories, compromise of a single developer device can spread to secondary compromises across multiple clouds, CI/CD pipelines, and source repositories. Hypothesis No additional hypotheses. Unverified items are documented under "Unknowns and Additional Investigation." 13. MITRE ATT&CK Mapping | ID | Technique | Confidence | Basis | | --- | --- | --- | --- | | T1195.002 | Supply Chain Compromise: Compromise Software Supply Chain | high | OVHcloud confirmed official release binary replacement, distinct from per-endpoint execution success counts. Definition | | T1552.001 | Unsecured Credentials: Credentials In Files | high | Official analysis describes sample capabilities to collect credential files such as cloud configurations and SSH keys. Definition | | T1005 | Data from Local System | high | Official analysis lists local files such as development tool databases and histories as collection targets. Definition | | T1560 | Archive Collected Data | high | The sample archives the collection directory. Because distinction of specific utilities/libraries is unconfirmed, it is limited to the parent technique. Definition | 14. Unknowns and Additional Investigation - Out of approximately 250 downloads, the exact number of endpoints where the binary was actually executed - The number of victims whose collected archives were successfully exfiltrated externally - The presence, absence, and scope of subsequent abuse using stolen secrets - The full activity history spanning from the developer key theft in October 2025 to the release tampering in October 2026 - Because it remains unconfirmed whether external exfiltration uses the same channel as existing command-and-control communications, mapping to T1041 (Exfiltration Over C2 Channel) is withheld. 15. Impact on SOCs and Organizations For endpoints that downloaded the tampered CLI during the affected window and executed it at any later time, do not conclude remediation solely by deleting the binary or updating. Rotate all secrets present on those devices—such as cloud, SSH, Kubernetes, GitHub, and AI tools—and verify downstream cloud and SaaS audit logs for unauthorized activity. 16. Summary by Role - For SOCs: Check for outbound traffic from the official CLI process to Solana RPC endpoints or external exfiltration destination IPs, and investigate traces of envchecker-[0-9]{9,10} directory creation, credential file enumeration, and archive creation immediately following ovhcloud binary execution. - For Administrators: Do not execute suspicious binaries; cross-reference them against official malicious hashes and temporary envchecker directories for deletion, and replace them with v0.16.0 or later. Because replacement alone does not resolve leaked credentials or existing subsequent compromises, a comprehensive revocation and reissuance of target secrets is required. - For Users: If you encounter suspicious notifications, errors, or authentication requests, do not retry the operation on your own; contact an administrator promptly.

    1 reaction
  6. OVHcloud CLI Release Hijack: Verify Downloads, Lock Releases If you installed or updated the OVHcloud CLI (ovhcloud) between 12:47 and 14:21 UTC on 19 October 2026 and ended up on v0.11.0 through v0.15.0, treat every secret readable from that machine as stolen. An attacker used a hijacked developer account to replace the release archives, and OVHcloud's own advisory says the build was meant to harvest secrets from disk[[1]](#cite-1). The fix for maintainers is one checkbox: GitHub immutable releases lock a published release's assets and tag[[7]](#cite-7). Below: who is affected, what to do tonight, why mutable release assets made this possible, a table of defences, how to switch immutability on, and how to verify a CLI before you run it. TL;DR - Affected: ovhcloud-cli v0.11.0 to v0.15.0 downloaded 12:47 to 14:21 UTC on 19 Oct 2026 (macOS, Linux, Windows x86_64 archives). v0.10.0 and v0.16.0 are listed as clean[[1]](#cite-1). - Do not run the binary to check it. Hash it and compare against the five MD5 values in OVHcloud's advisory, or look for an envchecker- folder in your temp directory. - If you are affected: rotate cloud, SSH, Git, Docker, Kubernetes and AI tooling credentials from a different machine, delete the binary, then install v0.16.0. - Root cause: release immutability was off, so a privileged account could overwrite assets on old releases without touching CI[[5]](#cite-5). - Maintainers: Settings, Releases, Enable release immutability. It only applies to future releases[[8]](#cite-8). - Users: pin a hash in CI and run gh release verify-asset. A checksums file inside a mutable release proves nothing, because it was swapped too[[6]](#cite-6). What happened on 19 October 2026 The advisory (GHSA-862f-55f5-vmvw, severity High, no CVE) says a compromised OVHcloud developer GitHub account was used to replace release binaries with malicious builds. Source code and the build chain were not affected, and no other repositories were touched[[1]](#cite-1). The Hacker News adds a detail that matters for defenders: the bad build was a plain go build from a later commit, uploaded on top of existing releases, so the release workflow never ran during the window[[5]](#cite-5). A downstream user caught it. Their CI pinned the SHA-256 of the Linux arm64 tarball, the pin started failing, and they opened issue #300 on the repository at about 13:50 UTC[[2]](#cite-2)[[6]](#cite-6). A maintainer replied that all binaries involved were deleted at 16:21 GMT+2 (14:21 UTC), and v0.16.0 followed as an immutable release with a signed tag[[2]](#cite-2)[[3]](#cite-3). Versions, platforms and the time window | Item | Detail | Source | | --- | --- | --- | | Affected releases | v0.11.0, v0.12.0, v0.13.0, v0.14.0, v0.15.0 | OVHcloud advisory[[1]](#cite-1) | | Clean releases | v0.10.0 and earlier, v0.16.0 and later | OVHcloud advisory[[1]](#cite-1) | | Affected platforms | Darwin arm64, Darwin x86_64, Linux arm64, Linux x86_64, Windows x86_64 | OVHcloud advisory[[1]](#cite-1) | | Not replaced | Linux i386, Windows i386, Windows arm64, WASM build | OpenSourceMalware[[6]](#cite-6) | | Exposure window | 12:47 to 14:21 UTC (14:47 to 16:21 UTC+2) on 19 Oct | OVHcloud advisory[[1]](#cite-1) | Press coverage disagrees on timing, so here is how to read it. BleepingComputer reports the compromised release appearing at 14:47 and being blocked at 16:21 with no timezone stated[[4]](#cite-4). Those are Paris times. The Hacker News gives 12:47 to 14:21 UTC[[5]](#cite-5). OpenSourceMalware's 12:47 to about 13:12 is the span in which the five releases were overwritten, not how long the files stayed up[[6]](#cite-6). The advisory's UTC window of 12:47 to 14:21 is the one to use. Anything downloaded from those five releases before 12:47 UTC is outside it, per the advisory. How people actually got hit According to The Hacker News, the exposed paths were the official install script (which does not check a hash), manual downloads from the five release pages, CI jobs fetching without a pinned hash, and the CLI's own upgrade command from v0.12.0 to v0.14.0 on macOS and Linux. The same report lists Homebrew (the cask pinned the original SHA-256), go install and source builds, and the Docker image as not exposed[[5]](#cite-5). Sources disagree on Homebrew: OpenSourceMalware lists the cask as an exposed path[[6]](#cite-6), while The Hacker News says it checked the tap history and the pinned hash would have made brew refuse the swapped file. OVHcloud's advisory does not mention Homebrew. That split is the whole story of this post: every path that verified a hash held up, and every path that trusted the release URL did not. Is it GlassWorm? OpenSourceMalware links the compromised account to the GlassWorm malware family. The evidence: a Solana wallet in the account's earlier force-pushed repositories that appears in public GlassWorm indicator lists. The researchers themselves call the link to the October swap their inference, and no October binary has been tied to GlassWorm because no copy was preserved[[6]](#cite-6). Treat the attribution as tentative. It does not change what you do. What to do tonight if you may be affected Work through this in order. Rotation comes before the upgrade, because installing v0.16.0 does nothing about keys that were already copied. 1. Find the binary and hash it without running it. The advisory lists MD5 values for the malicious binaries: Darwin arm64 6f2f086239f3d88eb2750e871901927d, Darwin x86_64 347e65eb7f2d78d1c6872690272a6cc3, Linux arm64 01f57206d37c28cf711677f612052913, Linux x86_64 301bff0b51980b9e76c93633e7cfd3bd, and Windows 6a3cf153338c416169cda2fe704c8848[[1]](#cite-1). 2. Look for the dropped folder. A directory named envchecker- followed by random digits in your temp directory means the malware ran[[1]](#cite-1). 3. Rotate from a different machine. The advisory names cloud, SSH, Git, Docker, Kubernetes and AI assistant tooling credentials[[1]](#cite-1). OpenSourceMalware's list adds package-manager tokens and .env files[[6]](#cite-6). OVHcloud's CEO told affected users to change every secret on disk, per BleepingComputer[[4]](#cite-4). 4. Delete the binary, then install v0.16.0. 5. Check CI. Any pipeline that downloaded the CLI in the window without a pinned hash ran the swapped build on a runner that holds deploy credentials. Hashing a binary is the easy part. Knowing what was on disk is the hard part. If you need an inventory, the [AI Provider Key Hygiene Kit](/product/ai-provider-key-hygiene-kit) scans files and git history for AI provider keys and ships a rotation runbook. The same rotate-what-was-on-disk logic applied in the [OpenCode console breach checklist](/blogs/opencode-console-breach-rotate-openai-anthropic-keys-checklist-2026), and the order of operations is identical: revoke first, investigate second. Why it worked: release assets were mutable A GitHub release is a page with files attached. Unless the repository opts in to immutability, anyone with write access can delete an attached file and upload a different one under the same name. The tag keeps pointing at the same commit, the source archive looks fine, and the release date does not change. OVHcloud's CEO said the cause was the immutability option being disabled, which let a sufficiently privileged account modify existing releases directly, bypassing the CI/CD checks, per BleepingComputer[[4]](#cite-4). The advisory's own scope line fits: the pipelines were not the weak point[[1]](#cite-1). OpenSourceMalware lists the contributing weaknesses beyond mutability: releases published under personal accounts, a peripheral contributor holding release-asset write permission, an install script that skips checksum verification, no provenance or signing before v0.16.0, and no private vulnerability reporting channel, so disclosure happened in a public issue[[6]](#cite-6). The checksum file was no help either. The same report says checksums.txt was one of the six files replaced on each affected release[[5]](#cite-5)[[6]](#cite-6). A hash that lives next to the file it vouches for is only a typo check. Defences compared: what each stops and who has to act | Defence | What it stops | What it does not stop | Who acts | | --- | --- | --- | --- | | GitHub immutable releases | Replacing or deleting assets, and moving or deleting the tag, on a published release[[7]](#cite-7) | Releases published before it was switched on[[8]](#cite-8). A compromised account cutting a brand-new release, which is a new, separately visible event | Maintainer | | Release attestation (generated automatically for immutable releases) | Lets anyone confirm a local file matches an asset on the release[[7]](#cite-7) | Malicious code that was in the release when it was published | Maintainer publishes, user verifies | | Checksums file inside the same release | Corrupted downloads | A swapped release, because the attacker replaces the checksums too[[6]](#cite-6) | Both, and low value | | Checksum or signature published somewhere the uploader cannot edit | A swap by anyone who can only touch the release page | A compromised maintainer machine or signing key | Maintainer publishes, user checks | | Hash pinned in your CI or install script | Any swap after you recorded the hash. This is what exposed the incident[[2]](#cite-2) | A release that was already bad when you pinned it | User | | Package manager with pinned hashes (Homebrew cask) | Same swap, because the cask held the original SHA-256, per The Hacker News[[5]](#cite-5) | A maintainer who updates the pin to a bad file | Packager | | Install script that downloads and runs with no hash check | Nothing | Everything above | Maintainer should fix; user should avoid | Two rows deserve a sentence each. Immutability is not a malware filter: it freezes whatever you published, good or bad, and it cannot stop an attacker from publishing a new release under a new tag. What it removes is the quiet rewrite of a trusted old release, which is exactly what let a v0.11.0 download from April turn hostile in October. And the signed-checksums row is a general pattern, not something OVHcloud shipped. Where a signature key lives matters more than the format. For maintainers: turn on immutable releases GitHub's documentation gives the steps[[8]](#cite-8). One repository 1. Open the repository, then Settings (under the ⋯ menu if it is hidden). 2. Scroll to the Releases section and select Enable release immutability. A whole organization 1. Open the organization, then Settings. 2. In the sidebar, under Code, planning, and automation, open Repository and click General. 3. In the Releases section, change the No policy dropdown to All repositories or Selected repositories. 4. For Selected repositories, click the gear icon, pick the repositories, and click Select repositories. Read the caveat before you celebrate: the docs say immutability applies only to future releases[[8]](#cite-8). Enabling it today does not retroactively lock last year's releases. The docs say nothing more about releases published before the switch, so for anything you must stand behind, cut a fresh release and point people at it. That is what OVHcloud did with v0.16.0, which its release page labels as an immutable release where only the title and notes can be edited[[3]](#cite-3). The docs also describe a publishing order that fits immutability: create the release as a draft, attach every asset, then publish, so nothing is missing at the moment it locks[[7]](#cite-7). Creating an immutable release automatically generates a release attestation that records the tag, the commit SHA and the assets[[7]](#cite-7). What else to change on the same afternoon - Audit who holds write access on release-publishing repositories. In this incident the account was a contributor, not a core maintainer[[6]](#cite-6). - Publish releases from a bot or organization-owned identity driven by your workflow, not from a person's account. - Turn on private vulnerability reporting. OVHcloud enabled it after the incident[[2]](#cite-2), and the reporter here had to use a public issue. - Make your install script check a hash, or delete it and point people to a package manager that pins one. - Sign tags. The v0.16.0 tag is signed, though its page flags the signing key as expired[[3]](#cite-3). A signature you cannot trust the key for is weaker than it looks, so keep keys current. For users: verify a CLI before you run it You have three checks, from cheapest to strongest. None requires running the download. 1. Hash it On Linux, sha256sum ovhcloud-cli_Linux_arm64.tar.gz. On macOS, shasum -a 256 ovhcloud-cli_Linux_arm64.tar.gz. Compare against a value you got from somewhere other than the release page you downloaded from: the maintainer's docs, a package manager, or the value you recorded last time. If you only have a browser, the [hash generator](/tools/hash-generator) has a file mode that computes MD5, SHA-1, SHA-256 and SHA-512 for a file you drop in, which is handy for matching the advisory's MD5 list. For the incident here, OpenSourceMalware published SHA-256 values for the v0.15.0 Linux arm64 archive: the swapped file ended in ...28933cb and the original in ...b80e0[[6]](#cite-6). 2. Verify against the release itself GitHub's documentation shows two commands for releases that are immutable[[9]](#cite-9): # confirm the release exists and is immutable gh release verify v0.16.0 --repo ovh/ovhcloud-cli # confirm a local file is an exact match for an asset on the release gh release verify-asset v0.16.0 ./ovhcloud-cli_Linux_arm64.tar.gz --repo ovh/ovhcloud-cli Run them inside a clone of the repository, or add gh's repository flag. The first command answers whether the release can still change under you. The second answers whether your file is the one attached to it. The docs add that source zip and tarball downloads cannot be checked this way, because GitHub generates them on request[[9]](#cite-9). In the web interface, an immutable release shows an Immutable label below its title[[9]](#cite-9). OpenSourceMalware also recommends gh attestation verify for v0.16.0[[6]](#cite-6). We ran gh attestation verify ovhcloud-cli_Linux_arm64.tar.gz --repo ovh/ovhcloud-cli on 20 October and got an HTTP 404: v0.16.0 has no build-provenance attestation, only the release attestation that GitHub creates for immutable releases. gh release verify-asset checks that one, and it passed on the same file. So use verify-asset for this CLI, and do not read a failed gh attestation verify as proof of tampering. 3. Pin it where an attacker cannot edit it The reporter of issue #300 never ran a verify command. They had a SHA-256 in CI, and the build broke when the file changed[[2]](#cite-2). Pin the hash in your repository, in a Dockerfile, in a bootstrap script. Update it by pull request, with a person reading the diff. A failing pin is the cheapest intrusion detector most teams will ever deploy. Pipelines deserve extra attention because they hold the most valuable secrets and the least human supervision. If your CI downloads tools with curl and pipes to a shell, you have the exposure OVHcloud users had. The [SecretsSafe CI/CD secrets audit pack](/product/secretssafe-cicd-secrets-audit-pack) is a checklist for finding which jobs hold which credentials, which tells you the blast radius before an incident does. Frequently asked questions Am I affected if I installed the CLI with Homebrew? Sources disagree. The Hacker News reports the Homebrew cask pinned the original SHA-256 and was not exposed, along with go install, source builds and the Docker image[[5]](#cite-5). OpenSourceMalware lists the cask as exposed[[6]](#cite-6), and the advisory does not mention Homebrew. The advisory's own scope is anyone who downloaded the five releases in the 12:47 to 14:21 UTC window[[1]](#cite-1). If you cannot say which route your machine used, hash the binary. Does updating to v0.16.0 fix it? It replaces the binary. It does not revoke credentials that a malicious build already read. Rotate first, from a clean machine, then upgrade. Would immutable releases have prevented this? The CEO's stated cause is that the setting was off and a privileged account could edit existing releases[[4]](#cite-4). With it on for those releases, overwriting their assets would not have been possible, per GitHub's description of what is locked[[7]](#cite-7). It would not stop a hijacked account from publishing a new release, which is why verification on the user side still matters. Why not trust the checksums.txt on the release page? Because in this incident it was swapped along with the archives, per The Hacker News and OpenSourceMalware[[5]](#cite-5)[[6]](#cite-6). A checksum is only evidence if the attacker could not have edited it. Is the GlassWorm link confirmed? No. The researchers call it inference from shared account identity, and no copy of the October binary has been analyzed publicly[[6]](#cite-6). OVHcloud's advisory does not attribute the attack to any named group[[1]](#cite-1). Does the advisory say what the malware sent out? The advisory calls the builds malicious and tells affected users to treat secrets as compromised[[1]](#cite-1). The Hacker News notes OVHcloud has not said which files the binary read or where it sent data[[5]](#cite-5). Assume the worst for anything on the disk. Sources 1. OVHcloud: GHSA-862f-55f5-vmvw, ovhcloud-cli security incident (accessed 20 October 2026) 2. ovh/ovhcloud-cli issue #300 (accessed 20 October 2026) 3. ovh/ovhcloud-cli release v0.16.0 (accessed 20 October 2026) 4. BleepingComputer: OVHcloud CLI releases backdoored on GitHub to steal developer secrets (accessed 20 October 2026) 5. The Hacker News: hackers hijack five OVHcloud CLI releases (accessed 20 October 2026) 6. OpenSourceMalware: GlassWorm hacks OVH Cloud's CLI tool (accessed 20 October 2026) 7. GitHub Docs: immutable releases (accessed 20 October 2026) 8. GitHub Docs: preventing changes to your releases (accessed 20 October 2026) 9. GitHub Docs: verifying the integrity of a release (accessed 20 October 2026) --- Originally published at wowhow.cloud

  7. ziemlich passables post-mortem fuer <24h imho... github.com/ovh/ovhcloud-cli/security/advisories/G…

    1 like
  8. Reddit · · r/KibernetinisSaugumas · u/Sarunas · ovh/ovhcloud-cli

    OVHcloud CLI penkių versijų failai GitHub platformoje buvo pakeisti duomenų vagystės programa Spalio 19 d. per užvaldytą kūrėjo GitHub paskyrą buvo pakeisti OVHcloud CLI versijų v0.11.0–v0.15.0 failai. Kenkėjiški failai buvo pasiekiami apie pusantros valandos. Atsisiuntimų buvo apie 250. Pakeista programa vagia SSH raktus, debesijos prisijungimo duomenis, Kubernetes, npm ir Git konfigūraciją. Ji renka ir VS Code, Cursor bei DI asistentų duomenis. Šaltinio kodas ir kūrimo grandinė nepažeisti. Praktinė rekomendacija. Jei spalio 19 d. diegėte ar atnaujinote OVHcloud CLI, ieškokite laikinajame aplanke katalogo envchecker. Radę pėdsakų, iš švaraus įrenginio pakeiskite visus raktus ir slaptažodžius. Naudokite v0.16.0 ar naujesnę versiją. Šaltinis (OVHcloud saugumo pranešimas) github.com/ovh/ovhcloud-cli/security/advisories/G…

    2 points
  9. The OVHcloud CLI Swap Left a Fingerprint: A Script to Check Your Go Binaries On Monday, October 19, someone used a contributor's GitHub account to replace the download archives on five OVHcloud CLI releases (v0.11.0 to v0.15.0) with a build that, in CEO Octave Klaba's words, was meant to "retrieve secrets from the disk." No tag moved, no workflow ran. The attacker uploaded new files to old releases and edited checksums.txt so the published hashes matched the bad binaries. What caught it was one customer's CI job that pinned the SHA-256 of ovhcloud-cli_Linux_arm64.tar.gz in their own repo. The job broke, they ran go version -m on the new binary, and the Go toolchain told them exactly what it was. I rebuilt that detection as a script, reproduced the attacker's build locally, and ran it against every Go binary on my machine. Code and real output below. The timeline, in minutes From issue #300 and The Hacker News (all UTC, Oct 19): 12:47 first asset replaced on v0.15.0 13:11 v0.13.0 checksums.txt replaced (last upload the reporter checked) 13:50 pinned-hash CI job fails, issue #300 filed 14:21 OVHcloud deletes the swapped files 17:16 clean v0.16.0 published as an immutable release $ python3 -c " from datetime import datetime as d f=lambda s:d.strptime(s,'%H:%M') print('swap window ', (f('14:21')-f('12:47')).seconds//60,'min') print('uploads took ', (f('13:11')-f('12:47')).seconds//60,'min') print('to detection ', (f('13:50')-f('12:47')).seconds//60,'min')" swap window 94 min uploads took 24 min to detection 63 min So the documented uploads took 24 minutes, and the bad files were downloadable for 94. Anyone on macOS, Linux x86_64/arm64 or Windows x86_64 who installed through install.sh or a "download latest release" step in that window got the swapped build. I read the repo's install.sh at tag v0.16.0: it downloads the tarball, untars it and installs it, with no checksum step. The fingerprint The reporter posted the build info of the swapped binary: mod github.com/ovh/ovhcloud-cli v0.15.1-0.20261013083505-5ead8ef9b43d+dirty build -ldflags="-s -w" build vcs.revision=5ead8ef9b43d354dfb5caadff803b11afc8c5c58 build vcs.modified=true Three things are wrong for a file attached to the v0.15.0 release: 1. The version is a pseudo-version (an untagged commit from Oct 13), not v0.15.0. 2. +dirty and vcs.modified=true: it was built with uncommitted changes. 3. A visible -ldflags line. The project's .goreleaser.yaml builds with -trimpath, and I confirmed in my shell that Go does not record -ldflags in build info when -trimpath is on. A visible -ldflags line means someone ran go build by hand. Since Go 1.24, go build stamps the main module version from the VCS tag and appends +dirty for uncommitted changes. That metadata survives -s -w stripping, and any binary built from a git checkout carries it unless the build passes -buildvcs=false. Reproducing the attacker's build I cloned ovh/ovhcloud-cli at v0.16.0 (commit 6ef70c2) and built four binaries: - clean: tag checkout, go build -trimpath - dirty: same, with one uncommitted line added - swapped: an untagged commit on top of the tag, one uncommitted line, -ldflags="-s -w", no -trimpath. This is the issue #300 recipe. - forged: a local tag named v0.16.0 moved to a different commit, so the binary claims the right version with the wrong code Then I asked the Go module proxy which commit the real tag points to: $ curl -s https://proxy.golang.org/github.com/ovh/ovhcloud-cli/@v/v0.16.0.info {"Version":"v0.16.0","Time":"2026-10-16T14:38:10Z","Origin":{"VCS":"git", "URL":"https://github.com/ovh/ovhcloud-cli", "Hash":"6ef70c2389cd22c72821cf8d435365d0dcbe2729","Ref":"refs/tags/v0.16.0"}} The Origin.Hash is the independent reference the script compares against. A GitHub release page can be edited by any account with write access. The proxy record and sum.golang.org ("an auditable checksum database") sit outside GitHub, so a hijacked account cannot edit them. The script gobin_audit.py reads build info from every Go binary in your $PATH (or the paths you pass), checks the commit against the proxy, and exits 1 on a FAIL so you can drop it into CI. Read-only, standard library only, needs go on PATH. def audit(path): info = build_info(path) # parses `go version -m` text output if not info: return None # not a Go binary main = info.get("Main") or {} mod, ver = main.get("Path", "?"), main.get("Version", "") s = {x["Key"]: x["Value"] for x in info.get("Settings", [])} rev, dirty = s.get("vcs.revision"), s.get("vcs.modified") == "true" dirty = dirty or ver.endswith("+dirty") tag = ver.replace("+dirty", "") findings = [] if ver in ("", "(devel)"): findings.append(("WARN", "no version stamp, cannot map to a tag")) elif PSEUDO.search(tag): if dirty: # the issue #300 signature findings.append(("FAIL", f"local dirty build of an untagged commit ({ver})")) else: findings.append(("WARN", f"untagged commit (pseudo-version {ver})")) elif rev: if dirty: findings.append(("WARN", "built with uncommitted changes (+dirty); can be legit")) want = proxy_commit(mod, tag) # Origin.Hash from proxy.golang.org if want and want.startswith("error"): findings.append(("INFO", f"proxy lookup failed: {want}")) elif want and want != rev: findings.append(("FAIL", f"commit {rev[:12]} != tag {tag} commit {want[:12]}")) elif want: findings.append(("OK", f"commit matches {tag} on {PROXY}")) if not rev: findings.append(("INFO", "no vcs.revision embedded; compare sha256 with a checksum you trust")) ... The full file (133 lines, including build_info, proxy_commit with the proxy's !lowercase path escaping, and the PATH walker) is at the end of this post. Output against my four builds: $ python3 gobin_audit.py ovhcloud-clean ovhcloud-dirty ovhcloud-swapped ovhcloud-forged ovhcloud-clean module github.com/ovh/ovhcloud-cli v0.16.0 (go1.27.1) sha256 8364f5294885acdaf7c6510927d7b54910c9d5bae9031f770b885c4e615a2d72 flags -trimpath=true OK commit matches v0.16.0 on https://proxy.golang.org ovhcloud-dirty module github.com/ovh/ovhcloud-cli v0.16.0+dirty (go1.27.1) sha256 d124b4a12fa22fdc9b072f1e5682c7a3829df7266e0f483c2e970598cae12a26 flags -trimpath=true WARN built with uncommitted changes (+dirty); can be legit OK commit matches v0.16.0 on https://proxy.golang.org ovhcloud-swapped module github.com/ovh/ovhcloud-cli v0.16.1-0.20261020124243-08d2b7bdd60b+dirty (go1.27.1) sha256 93af002eb174dd5c7fc79266fb11fa7e899d07fd42afead346c640a335df5cb9 flags -ldflags="-s -w" FAIL local dirty build of an untagged commit (v0.16.1-0.20261020124243-08d2b7bdd60b+dirty) ovhcloud-forged module github.com/ovh/ovhcloud-cli v0.16.0 (go1.27.1) sha256 21c9b4f2e8a625e16299469a5a32dc97eaa95242ad24948ad6945c2638898f70 flags -trimpath=true FAIL commit 08d2b7bdd60b != tag v0.16.0 commit 6ef70c2389cd 4 Go binaries checked, worst result: FAIL exit=1 Why +dirty on a tagged build is only a WARN: The Hacker News reports that the genuine v0.16.0 release itself reports v0.16.0+dirty. My guess is the go mod tidy before-hook in the goreleaser config, but I have not confirmed it. Either way, failing on +dirty alone would have flagged the clean fix. Then I ran it with no arguments, which walks $PATH: $ python3 gobin_audit.py | tail -1 15 Go binaries checked, worst result: WARN 6 OK (gh, golangci-lint, containerd, containerd-shim-runc-v2, ctr, runc), 9 WARN, 0 FAIL. The WARNs were all distro-packaged or toolchain binaries (docker, git-lfs, age, go itself) built without VCS stamps. That is normal; for those the script prints the SHA-256 for you to compare against the distro's own checksums. Honest caveats - Build info is just bytes. A careful attacker builds with -buildvcs=false or fakes the stamp. This catches sloppy swaps like this one (Klaba called the binary's quality "poor"), and it will not catch a careful one. - The -ldflags signal is project-specific. gh v2.89.0 on my machine shows a full -ldflags line and is genuine. Compare against the project's own release config. - It only covers Go. Rust, Node and Python CLIs need their own checks. The checklist I now run If you consume CLIs from GitHub releases: 1. Pin the SHA-256 in your own repo. A checksums.txt in the same release protects you from nothing here, because the attacker replaced it too. This is the check that caught the attack: $ echo "5c2beb56e6d83a4b426565a1557791ef759316abcc4effb38dd627c90aeb80e0 ovhcloud-cli_Linux_arm64.tar.gz" | sha256sum -c - ovhcloud-cli_Linux_arm64.tar.gz: FAILED sha256sum: WARNING: 1 computed checksum did NOT match (Run against a stand-in file; the hash is the original v0.15.0 arm64 archive from issue #300.) 2. For Go tools, install through the module proxy. go install github.com/ovh/ovhcloud-cli/cmd/ovhcloud@v0.16.0 fetched the module zip whose hash, h1:qu7za9IqNOQQcV3ddmLdDSvKLwmaIAeA7tsAe6lV4kY=, matches the entry I pulled from sum.golang.org/lookup. The issue #300 reporter switched to exactly this, and source builds were not affected. 3. Run gobin_audit.py on dev laptops and CI images weekly. 4. For immutable releases, gh release verify-asset <tag> <file> checks GitHub's signed attestation. I could not test it here because my sandbox blocks the GitHub API. If you ran an affected build: rotate everything readable on that machine, from a different machine. My secrets_on_disk.sh lists what to rotate (paths, sizes and dates only, never contents). Against a throwaway home directory with planted files: $ env -i HOME=./home PATH=/usr/bin:/bin OVH_CONSUMER_KEY=x STRIPE_SECRET_KEY=y bash secrets_on_disk.sh ./app PATH BYTES MODIFIED ./home/.ovh.conf 80 2026-10-20 12:44:39 ./home/.aws/credentials 54 2026-10-20 12:44:39 ./home/.kube/config 15 2026-10-20 12:44:39 ./home/.npmrc 35 2026-10-20 12:44:39 ./home/.ssh/id_ed25519 2 2026-10-20 12:44:39 env OVH_CONSUMER_KEY env STRIPE_SECRET_KEY dotenv ./app/.env.production If you publish CLIs: turn on release immutability (it only locks releases created after you enable it, so republish old ones), enable private vulnerability reporting (issue #300 was public because there was none), and build with -trimpath plus a version ldflag so a hand-built impostor stands out. Full script: gobin_audit.py #!/usr/bin/env python3 """gobin_audit.py: check Go binaries against the tag they claim to be. For every Go binary found (in the paths given, or in $PATH), read the build info the Go toolchain embeds and flag: FAIL binary says it is tag vX but carries a different commit than the one the Go module proxy recorded for vX FAIL local dirty build of an untagged commit (the OVHcloud CLI signature) WARN untagged commit, no version stamp, or +dirty on a tagged build INFO no VCS info embedded, so the tag cannot be checked Needs: go on PATH, network access to proxy.golang.org. Read-only. """ import hashlib, json, os, re, stat, subprocess, sys, urllib.request PROXY = os.environ.get("GOAUDIT_PROXY", "https://proxy.golang.org") PSEUDO = re.compile(r"-(0\.)?\d{14}-[0-9a-f]{12}(\+incompatible)?$") def build_info(path): # parse text output: Go 1.24 has no -json flag for go version -m r = subprocess.run(["go", "version", "-m", path], capture_output=True, text=True) lines = r.stdout.splitlines() if r.returncode != 0 or not lines or ": go" not in lines[0]: return None info = {"GoVersion": lines[0].rsplit(": ", 1)[1], "Main": {}, "Settings": []} for line in lines[1:]: parts = line.strip("\t").split("\t") if parts[0] == "mod" and len(parts) >= 3: info["Main"] = {"Path": parts[1], "Version": parts[2]} elif parts[0] == "build" and "=" in parts[1]: k, v = parts[1].split("=", 1) info["Settings"].append({"Key": k, "Value": v}) return info def escape(mod): # module path escaping used by the proxy protocol return "".join("!" + c.lower() if c.isupper() else c for c in mod) def proxy_commit(mod, ver): url = f"{PROXY}/{escape(mod)}/@v/{ver}.info" try: with urllib.request.urlopen(url, timeout=15) as resp: return json.load(resp).get("Origin", {}).get("Hash") except Exception as e: return f"error: {e}" def sha256(path): h = hashlib.sha256() with open(path, "rb") as f: for chunk in iter(lambda: f.read(1 << 20), b""): h.update(chunk) return h.hexdigest() def audit(path): info = build_info(path) if not info: return None main = info.get("Main") or {} mod, ver = main.get("Path", "?"), main.get("Version", "") s = {x["Key"]: x["Value"] for x in info.get("Settings", [])} rev, dirty = s.get("vcs.revision"), s.get("vcs.modified") == "true" dirty = dirty or ver.endswith("+dirty") tag = ver.replace("+dirty", "") findings = [] if ver in ("", "(devel)"): findings.append(("WARN", "no version stamp, cannot map to a tag")) elif PSEUDO.search(tag): if dirty: # the issue #300 signature: local build of an untagged commit findings.append(("FAIL", f"local dirty build of an untagged commit ({ver})")) else: findings.append(("WARN", f"untagged commit (pseudo-version {ver})")) elif rev: if dirty: findings.append(("WARN", "built with uncommitted changes (+dirty); can be legit")) want = proxy_commit(mod, tag) if want and want.startswith("error"): findings.append(("INFO", f"proxy lookup failed: {want}")) elif want and want != rev: findings.append(("FAIL", f"commit {rev[:12]} != tag {tag} commit {want[:12]}")) elif want: findings.append(("OK", f"commit matches {tag} on {PROXY}")) if not rev: findings.append(("INFO", "no vcs.revision embedded; compare sha256 with a checksum you trust")) # release pipelines usually build with -trimpath, which hides -ldflags; # a visible -ldflags line means a build that skipped -trimpath flags = " ".join(f"{k}={v}" for k, v in s.items() if k in ("-trimpath", "-ldflags")) return {"path": path, "module": mod, "version": ver, "go": info.get("GoVersion"), "sha256": sha256(path), "flags": flags or "(none recorded)", "findings": findings} def candidates(paths): for p in paths: if os.path.isfile(p): yield p elif os.path.isdir(p): for name in sorted(os.listdir(p)): f = os.path.join(p, name) try: st = os.stat(f) except OSError: continue if stat.S_ISREG(st.st_mode) and st.st_mode & 0o111: yield f def main(): paths = sys.argv[1:] or os.environ.get("PATH", "").split(os.pathsep) seen, worst, n = set(), "OK", 0 rank = {"OK": 0, "INFO": 1, "WARN": 2, "FAIL": 3} for f in candidates(paths): real = os.path.realpath(f) if real in seen: continue seen.add(real) r = audit(f) if not r: continue n += 1 print(f"{r['path']}\n module {r['module']} {r['version']} ({r['go']})\n sha256 {r['sha256']}") print(f" flags {r['flags']}") for level, msg in r["findings"]: print(f" {level:<5} {msg}") if rank[level] > rank[worst]: worst = level print(f"\n{n} Go binaries checked, worst result: {worst}") sys.exit(1 if worst == "FAIL" else 0) if __name__ == "__main__": main() At Axionry, this kind of release-pipeline review is part of our fractional CTO work (from $3,000/mo, 10 to 20 hours a month) and of the technical due diligence we do for investors. More hands-on posts like this on the Axionry blog. Sources: ovh/ovhcloud-cli issue #300, The Hacker News, BleepingComputer, Go 1.24 release notes, Go checksum database, GitHub immutable releases changelog, GitHub: verify release integrity

  10. Release assets of v0.13.0–v0.15.0 replaced on 2026-10-19 with a dirty build of a later commit · Issue #300 · ovh/ovhcloud-cli - compromised release

Achievements

Awards earned by the repositories ovh owns. Select an award to embed its badge.

No awards yet

Repositories earn awards by reaching the top three in a completed trending day or week.

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.