Cloud & DevOpsSecurity

wfx-loot: 4,837 GitHub Accounts Stole Your CI Secrets

On November 10, an attacker with 4,837 hijacked GitHub accounts opened pull requests in 61,764 repositories. The title was deliberately forgettable: docs: dependency audit notes. In over 1,806 of those repos, a CI workflow ran the payload, exfiltrated secrets, then deleted its own logs. GitHub has not published an official statement. And if your team’s incident response was “rotate the secrets and move on,” you may still have a live backdoor in AWS or Azure.

How the Attack Worked

Aikido Security, which discovered and named the campaign, documented a three-phase attack. First, a stolen token opens a probe pull request from a branch named wfx-docs. It adds a file called docs/wfx-audit.md — innocuous-looking documentation. This is just a probe to confirm write access.

If the probe succeeds, the attacker injects a roughly 1,500-line shell script through one of three vectors: appended to an existing GitHub Actions workflow file, embedded in an npm postinstall hook (meaning it runs on npm install in your CI), or dropped as a new throwaway workflow on a side branch. Commit messages follow the same camouflage pattern: ci: refresh build cache, chore: add ci helper, ci: restore.

The script runs, exfiltrates everything it can reach, then attempts to cover its tracks — reverting the malicious commit and deleting the workflow run and its logs. If you’re checking your Actions history, you may find nothing there.

What It Took

The campaign was not limited to GitHub Actions secrets. The stealer explicitly targets eight token families: GitHub tokens in all formats (ghp_, gho_, ghu_, ghs_, github_pat_), AWS AKIA keys, Anthropic API keys (sk-ant-), OpenAI keys (sk-proj-, sk-svcacct-), Hugging Face tokens (hf_), GitLab personal access tokens, and JWTs — which catches cloud provider OIDC tokens on the way out.

Beyond static credentials, the script sweeps runner process memory, shell histories, SSH and GPG keys, Vault and Kubernetes secrets, and package-registry publish tokens. Around 50 of the 4,837 compromised accounts hold publish rights on npm, PyPI, Go modules, Packagist, and crates.io. Two packages have been confirmed poisoned: digitalelvis/neuronai-studio version 3.14.3 on Packagist and the Go module github.com/onuragtas/docker-env versions 1.0.278 and 1.0.280.

The Part Most Teams Are Missing

Standard incident response — rotate every secret, re-deploy — does not close this breach. The campaign plants cloud backdoors specifically designed to survive that playbook.

In AWS, the script creates new access keys and rewrites IAM role trust policies to allow any principal via sts:AssumeRoleWithWebIdentity. In Azure, it adds Entra ID federated credentials with the name pattern wfx-ci-*. Any job with permissions: id-token: write can mint fresh cloud sessions — and those sessions remain valid after you rotate your GitHub secrets. The attacker can re-enter your cloud environment through the backdoor long after your CI pipeline looks clean.

This is not an edge case. It is the design intent of the campaign.

What to Do Now

Work through these four steps in order.

1. Check for IOCs. Search your organization’s pull requests for docs: dependency audit notes and branches named wfx-docs. Check git history since November 10 for commits titled ci: refresh build cache or chore: add ci helper. Even if nothing shows up, the script attempts to delete evidence — absence of a trace is not a clean bill of health.

2. Rotate all secrets. Not just the ones referenced in the affected workflow. Every repository, environment, and organization secret. Cloud keys across AWS, Azure, and GCP. AI provider API keys. Package registry publish tokens. Vault and Kubernetes credentials.

3. Audit your cloud for backdoors. In AWS: review IAM role trust policies for overly broad AssumeRoleWithWebIdentity trust, and look for access keys or sessions named wfx-* created after November 10. In Azure: check Entra ID applications and service principals for federated credentials named wfx-ci-*. This step is not optional if your repos ran any GitHub Actions between November 10 and 13.

4. Harden before the next campaign. Set GITHUB_TOKEN to read-only by default under Settings > Actions > General. Add an explicit permissions: block to every workflow file and grant only what that job needs. Scope OIDC trust to specific repositories, branches, and environments — not wildcards. Pin every third-party Action to its full commit SHA rather than a mutable tag like @v3. GitHub’s official hardening guide covers all of these steps in detail.

The Bigger Problem

GitHub Actions makes write access too easy to obtain and too easy to exploit. When a stolen credential from any collaborator on any branch is enough to inject code into CI, the attack surface is enormous. The Hacker News coverage confirms the scale: five days after an attack that probed over 61,000 repositories — the largest GitHub Actions supply chain attack on record by account count — there is still no security advisory from GitHub.

Rotating secrets is not an incident response plan. It is the first step of one. The rest involves cloud forensics most teams skip entirely.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *