Since 10 November, an attacker holding stolen tokens for 4,837 GitHub accounts has been slipping a credential stealer into CI pipelines, then usually erasing the evidence within minutes. The payload goes beyond grabbing secrets: it plants cloud backdoors built to survive the key rotation most teams will reach for first.
What happened
Aikido Security disclosed the campaign on 12 November and named it wfx-loot. The malware labels itself “wfx”, and the attacker calls the stolen data “loot”. At around 12:45 UTC on 10 November, the operator started working through a large stash of compromised GitHub credentials. Each stolen token was checked against every repository it could write to.
Aikido traced probe pull requests from 4,837 hijacked accounts across 61,764 repositories. In 10,431 of those, the account did not own the repository and got in through collaborator or organisation membership. About 92% of those pull requests were still open when Aikido checked, so most owners apparently have not noticed. Aikido saw signs that the payload actually ran in at least 1,806 repositories, and thinks the real number is higher.
SafeDep, working separately, counted 8,093 repositories hit with malicious commits up to 04:36 UTC on 12 November. It could only search public default branches, so private code is missing from that total.
A few packages were caught too. Packagist release 3.14.3 of digitalelvis/neuronai-studio contains the payload, and Go module github.com/onuragtas/docker-env has it in a workflow file in three versions (v1.0.278, v1.0.280, v1.0.282). The Go proxy has also cached a poisoned commit of github.com/vkuznet/gocurl. Even so, Aikido thinks the goal is harvesting CI secrets, not building a self-spreading worm.
This appears separate from October’s GhostAction wave. Some of the same accounts were hit, but Aikido believes a different actor is using different tooling and infrastructure.
The technical picture
For each repository the operator follows three steps. First, a pull request labelled “docs: dependency audit notes” is opened from a branch called wfx-docs, purely to confirm write access. Second, the stealer is pushed in one of three forms: around 1,500 lines spliced into an existing workflow, a hidden shell script wired to an npm postinstall hook, or a new workflow on a throwaway branch. SafeDep’s figures show workflow splicing dominates (7,309 repositories), ahead of the install hook (771). Third, the change is reverted and the workflow run and its logs are deleted. Often the only sign left is a gap in the run numbering.
The install hook fires on any npm install, so a developer laptop is as exposed as a build runner.
The payload itself is a plain, heavily commented shell script that runs in four stages. It gathers repository secrets, the job’s GITHUB_TOKEN and OIDC tokens, credential files for the major clouds and developer tools, SSH and GPG material, shell history and keys for AI services such as OpenAI and Anthropic. On self-hosted runners it also targets cloud instance metadata and Docker state.
It then escalates. It requests GitHub OIDC tokens and tries to exchange them for AWS, Google Cloud and Azure sessions, even where no such trust appears to be configured. In AWS it chains into other roles and creates long-lived access keys.
The persistence stage is the part defenders should study. In AWS it rewrites the trust policy of a role it has reached so that any principal can assume it. In Microsoft Entra ID it adds federated identity credentials with a wfx-ci- prefix to app registrations, letting workflows in the compromised repository authenticate as that application without any stored secret. The code also contains a routine to post forged “success” results under the names of required status checks, which would get past branch protection. SafeDep notes that none of its samples had this switched on.
Exfiltration went by HTTP POST to three servers on port 8080, or to a Telegram chat. Quieter channels that hide data inside GitHub’s own cache and artifacts exist in the code but were switched off, so finding no wfx artefacts proves nothing.

Why it matters for UK organisations
None of the reporting names UK victims, but the exposure does not depend on geography. Many UK software houses, fintechs and public sector digital teams run on GitHub Actions. Many have adopted OIDC federation into AWS, Azure or Google Cloud precisely because it was sold as the safer alternative to long-lived keys. wfx-loot shows the other side of that trade. If a pipeline can mint a cloud session, so can anyone who controls the pipeline.
The collaborator figure should also worry suppliers. More than 10,000 of the probe requests came through accounts that had access to someone else’s code. If a contractor or former team member still holds write access to your organisation’s repositories and their token is stolen, your secrets are in scope.
Expert view
What stands out to me is the discipline. Probe first, act fast, revert, then delete the logs: that is how a careful red team works, and it defeats the lazy check of “the branch looks clean, so we’re fine”. When we test CI/CD estates, the weak point is rarely GitHub itself. It is the trust relationship between the pipeline and the cloud, which is usually broader than anyone remembers configuring.
The persistence choices show the author knows how incident response normally goes. Most teams rotate secrets, revoke the obvious token and stop there. A wildcard trust policy or an extra federated credential on an Entra app survives all of that, and few organisations alert on either. In my experience, federated credentials on app registrations are among the least reviewed objects in a Microsoft tenant.
The unobfuscated code suggests volume mattered more than stealth this time. I would not bet on the next run being as noisy.
What to do now
- Search your organisation for wfx-docs branches, pull requests titled “docs: dependency audit notes”, and commits with the messages “chore: add ci helper”, “ci: refresh build cache” and “chore: add dependency audit workflow”. A probe on its own means the account’s token is compromised.
- Look for gaps in workflow run numbers on suspicious commits. Missing runs are the most reliable trace of execution.
- If a payload ran, rotate everything that workflow could read: repository, environment and organisation secrets, plus any cloud role it could assume.
- Hunt for persistence: AWS role trust policies with wildcard principals, new IAM access keys, CloudTrail sessions named wfx-*, and Entra app registrations with unfamiliar wfx-ci- federated credentials. Remove them. Rotation alone will not.
- Treat developer machines that ran npm install on an affected commit, or installed the named Packagist release, as compromised.
- Tighten access (Cyber Essentials user access control): enforce two-factor authentication across the GitHub organisation, prune stale collaborators and bots, and prefer short-lived, fine-grained tokens.
- Narrow OIDC trust (secure configuration): scope cloud role conditions to specific repositories, branches and environments, give workflows minimal default permissions, and require protected environments for deployment roles.
Bottom line
wfx-loot is a mass campaign built with an intruder’s patience: confirm access, strike briefly, clean up, and leave a back door in the cloud. If your engineers use GitHub Actions, check for the probe indicators today. Then audit cloud trust policies and Entra federated credentials, because that is where this attacker expects to come back in.
Sources
- Aikido Security: wfx-loot campaign pushes CI secret stealer to tens of thousands of repositories
- SafeDep: wfx: GitHub Actions credential stealer hits 8,000 repos
- The Hacker News: 4,837 hijacked GitHub accounts ran a CI secret stealer in 1,806+ repositories
- Help Net Security: Check your GitHub repos: a secret stealer hit tens of thousands of them