4,837 Accounts Hijacked. Your CI Secrets Walked Out.
A pull request titled “docs: dependency audit notes” arrived in thousands of repositories this week. It looked like routine housekeeping — a small documentation change, nothing to rush. Behind it was a test. And behind the test, a secret stealer that has already run in more than 1,800 repositories.
Aikido Security says an attacker used stolen credentials for 4,837 GitHub accounts to plant the stealer in repositories those accounts could write to. SafeDep counted 8,093 repositories that received malicious commits between 12:46 UTC Tuesday and 04:36 UTC Wednesday: in 7,309 the stealer was added to an existing workflow, and in 771 it arrived as an npm postinstall hook, which also runs on a developer’s machine during npm install.
The test came first
Every attack started the same way: a pull request from a branch named wfx-docs, testing whether the stolen account could write to the repository. Those test pull requests were opened in 61,764 repositories, and of the ones that came through collaborator or organization access, 92% were still open when Aikido checked. More were still arriving early on Wednesday morning — three checked by The Hacker News, opened between 05:04 and 05:38 UTC. The attack is still running.
Where the stealer ran, the attacker usually reverted the change within minutes and deleted the logs, usually along with the run itself — the evidence cleans itself up. Aikido’s warning is blunt: any account that opened a test pull request is compromised, even if the stealer never ran, and where it did run, every secret and cloud role available to the workflows should be treated as compromised.
Check for these signs, from Tuesday onward: branches wfx-docs, chore/ plus eight lowercase letters or digits, or ci-check- plus four digits; commit messages like “ci: refresh build cache” or “chore: add ci helper”. The stealer script’s SHA-256 is 89695abb392d5cfd4972672961e644bb46baa98aa1ed7173c2a2816c762735cf, and it sends data to 194.150.166.244, 18.143.168.96, or 153.75.82.159 on port 8080 — or to a Telegram chat. A missing run number on the attacker’s commit is the more reliable sign the stealer ran.

What the stealer takes
The stealer is thorough. It collects GitHub Actions secrets and variables, the workflow’s GITHUB_TOKEN, OIDC and Actions runtime tokens, AI service keys, and secrets in the runner’s own process memory. It reads credential files for AWS, Azure, GCP, Kubernetes, npm, PyPI, and SSH, and copies the repository, its last 100 commits, and recent workflow artifacts. On self-hosted runners it also takes cloud credentials from instance metadata, Docker state, and systemd units. Like the Claude Code secrets spill, except the attacker is not waiting for a leak — the stealer walks into the build system and takes the keys from the runner itself.
Built to survive rotation
Rotating the stolen credentials is necessary. It is not sufficient. The stealer uses those credentials to reach deeper into cloud accounts — and to leave backdoors that survive rotation. It exchanges GitHub OIDC tokens for AWS, GCP, and Azure sessions, creates long-lived IAM access keys, and can rewrite a role’s trust policy to open the role to any AWS account. It can also add wfx-ci- federated identity credentials to Azure AD applications, letting the compromised repository’s workflows sign in to Azure without a stored secret, even after every token has been rotated. It is the same trusted-access pattern behind the Qubole breach: once the trust relationship itself is theirs, the attacker does not need your password.
To find them, check Entra ID for wfx-ci-* federated credentials you did not create; CloudTrail for wfx-* AssumeRoleWithWebIdentity or AssumeRole sessions followed by CreateAccessKey or UpdateAssumeRolePolicy; GCP for GenerateAccessToken and SignJwt calls from your GitHub workload identity pool; and Vault for JWT logins from the GitHub OIDC issuer. If any show up, the rotation has to include the trust policies and federated credentials — not just the keys.
It reached the package registries
The stealer also reached at least one Packagist package and two Go modules through automated publishing triggers. Version 3.14.3 of the Packagist package digitalelvis/neuronai-studio is malicious — block it, pin v3.14.2 or earlier, and treat any machine that installed or opened it as compromised. Two versions of the Go module github.com/onuragtas/docker-env and a pseudo-version of github.com/vkuznet/gocurl carry the stealer only in workflow files; remove them. The stealer also reached 28 WebdriverIO repositories through commits authored as the bot account wdio-bot; no package release was affected, but the bot’s token should be treated as stolen. The accounts overlap with GhostAction’s October wave: October victims were about 1,000 times more likely to be used this week, and in more than 100 repositories the new stealer was added to October’s workflow files — though Aikido says it does not attribute November to the same actor at this stage.
What to check now
First, revoke the commit author’s tokens, OAuth app grants, SSH keys, and sessions, and turn on two-factor authentication — any account that opened a test pull request is compromised. Second, rotate every secret and variable the repository can read, then hunt the backdoors: wfx-ci- federated credentials in Entra ID, wfx-* role assumptions in CloudTrail, GitHub workload identity pool calls in GCP. Third, check the machines: anyone who ran npm install on an affected commit should treat that machine as compromised — the postinstall hook runs the stealer on the developer’s own computer, not just in CI.

The test is still arriving
The test pull requests were still arriving on Wednesday morning, hours after the campaign was disclosed. The attacker is not done. The fix list is short: revoke, rotate, hunt the backdoors, check the machines. Run it before the next test lands — because the next test is already on its way.



















