Navigation
Cybersecurity

Attack on the OVHcloud CLI: How GitHub Releases Were Overwritten and How to Protect Them

October 31, 2026 techy.sk

On Monday, October 19, 2026, an attacker who had taken control of an OVHcloud contributor’s GitHub account replaced the binaries in five existing releases of an official command-line tool. Neither the source code nor the build pipeline was altered. It was enough that the GitHub releases were not immutable. This article analyzes what happened based on available reports and shows how to secure your own releases by signing them via cosign and how to verify them before execution.

What happened

  • When: October 19, 2026, between 12:47 and 14:21 UTC (14:47 to 16:21 Central European Summer Time). The files were accessible for approximately 94 minutes.
  • What was affected: versions v0.11.0 through v0.15.0 of the ovhcloud-cli tool. According to OVHcloud, version v0.10.0 is unaffected. Reports indicate that the files were downloaded by roughly 250 people or systems.
  • How it happened: The attacker used stolen access to a contributor’s GitHub account and replaced files in existing releases with locally compiled malicious binaries. According to OVHcloud, the internal build systems were not compromised. The release workflow was not even running at the time.
  • Why it slipped through: release immutability was not enabled in the repository. An authorized user could therefore modify already published files directly on GitHub, without any checks by CI/CD.
  • Discovery: A customer reported the issue. OVHcloud deleted the files and released a clean, immutable version v0.16.0 that same evening.
  • What the malicious code did: According to OVHcloud, it was designed to collect secrets stored on disk. The company did not disclose exactly which files it read or where it sent them. Therefore, I did not include specific claims about Docker or Kubernetes configurations and databases from developer tools in this article.
  • Connection to GlassWorm: Some reports link the attack to the GlassWorm campaign. Another source notes that no copy of the October binary has been preserved, so a direct connection cannot be confirmed. According to OVHcloud, the account was compromised via a malicious extension on the developer’s personal device.

Why the “old, stable version” isn’t a myth

The common perception is that an older version from the official repository is safe because it has stood the test of time. This incident proves the opposite. If releases are subject to change, even an older version may suddenly differ from the one someone downloaded a year ago. Therefore, the same version tag does not guarantee the same content.

In addition, the project’s installation script downloaded the archive without verifying the hash. This also affected manual downloads.

Why Two-Factor Authentication Isn't Enough

Two-factor authentication protects logins. However, if an attacker steals a token or key that has already been issued, its use is not protected by the second factor. This distinction is important: in this case, the stolen keys were used to upload files. Therefore, the defense must also ensure that a compromised account cannot be used to silently alter releases.

Defense 1: Enable immutable releases

GitHub allows you to mark releases as immutable. Once published, files cannot be modified or deleted, and the tag cannot be moved. Enable this option in the repository settings (Releases section). For immutable releases, first create the release as a draft, upload the files, and then publish it. Check the current GitHub documentation for the exact path in the settings, as it is subject to change.

Defense 2: Sign artifacts using cosign

Cosign from the Sigstore project allows you to sign a file without managing a long-term key. This so-called keyless signature uses the identity of the GitHub Actions workflow. The verifier then does not check the “organization’s public key,” but rather verifies that the file was signed by a specific workflow in a specific repository. An attacker who only has stolen login credentials cannot produce such a signature without running the workflow.

For the action versions in the demo, pin them to the full commit hash rather than to a moving tag. Pinning a tag poses the same risk that has already been exploited in other supply chain attacks.

name: release
on:
  push:
    tags: ["v*"]

permissions:
  contents: read

jobs:
  build-sign-release:
    runs-on: ubuntu-latest
    permissions:
      contents: write      # vytvorenie vydania
      id-token: write      # keyless podpis cez OIDC
      attestations: write  # voliteľné: atestácia pôvodu
    steps:
      - uses: actions/checkout@<PLNY_HASH_COMMITU>   # v4
      - uses: actions/setup-go@<PLNY_HASH_COMMITU>    # v5
        with:
          go-version-file: go.mod

      - name: Build
        run: |
          mkdir dist
          CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -o dist/mytool-linux-amd64 ./cmd/mytool
          (cd dist && sha256sum mytool-* > SHA256SUMS)

      - uses: sigstore/cosign-installer@<PLNY_HASH_COMMITU>   # v3

      - name: Podpis artefaktov
        run: |
          for f in $(ls dist); do
            cosign sign-blob --yes --bundle "dist/$f.bundle" "dist/$f"
          done

      - uses: actions/attest-build-provenance@<PLNY_HASH_COMMITU>   # voliteľné
        with:
          subject-path: "dist/mytool-*"

      - name: Vydanie (koncept, potom zverejnenie)
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh release create "$GITHUB_REF_NAME" dist/* --draft --title "$GITHUB_REF_NAME" --generate-notes
          gh release edit "$GITHUB_REF_NAME" --draft=false

Adjust values such as mytool and paths should be adjusted according to the project.

Defense 3: Verify the signature before running

Downloading and running a tool from the internet without verifying it is exactly what led to the incident. The following script downloads both the binary and its signature package, verifies them, and only then installs them:

#!/usr/bin/env bash
set -euo pipefail

REPO="${REPO:?nastav napr. REPO=moja-org/moj-nastroj}"
TAG="${1:?verzia, napr. v1.2.3}"
ASSET="${2:?názov súboru, napr. mytool-linux-amd64}"

command -v cosign >/dev/null || { echo "Chýba cosign." >&2; exit 1; }

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
base="https://github.com/${REPO}/releases/download/${TAG}"

curl -fsSL -o "$tmp/$ASSET" "$base/$ASSET"
curl -fsSL -o "$tmp/$ASSET.bundle" "$base/$ASSET.bundle"

cosign verify-blob 
  --bundle "$tmp/$ASSET.bundle" 
  --certificate-identity "https://github.com/${REPO}/.github/workflows/release.yml@refs/tags/${TAG}" 
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" 
  "$tmp/$ASSET"

mkdir -p "${INSTALL_DIR:-$HOME/.local/bin}"
install -m 0755 "$tmp/$ASSET" "${INSTALL_DIR:-$HOME/.local/bin}/${ASSET%%-*}"
echo "Overené a nainštalované."

If verification fails, the script will terminate and nothing will be installed. This is a standalone script, not a Git hook. You can integrate it into your installation process, CI, or your organization’s package manager.

What this won't solve

  • A contributor with write access to the repository can theoretically trigger a workflow even on a new tag. Limit this by using tag protection (rulesets), mandatory workflow change reviews, and an environment requiring approval.
  • A signature won’t help those who never check the file. Verification must be part of the installation, not an optional step.
  • An update won’t help those who have already downloaded the malicious binary. The compromised copy of the keys is already out there.

If you were affected

  • Check to see if you installed or updated ovhcloud-cli and ran it during the specified time window (October 19, 2026, 2:47 p.m. to 4:21 p.m. Central European Summer Time). This also applies to the CI pipeline.
  • If so, remove the binary, install a clean version v0.16.0 or newer, and consider all secrets on that machine compromised.
  • Change your access keys, tokens, SSH keys, and passwords stored on disk. According to the founder of OVHcloud, updating the tool alone will not revoke a key that has already been copied.

What to Take Away From This

The attack did not require breaking encryption or the build pipeline. It was enough that the releases could be modified and that the downloader did not verify anything. Two measures that will resolve this are immutable releases on the publisher’s side and signature verification on the user’s side. Neither is complicated. Both must be enabled before anyone can use stolen credentials.

Share Article

You Might Be Interested