Daily Tech Now

Daily News on AI, Big Tech, Linux, Security & Gadgets

wfx-loot Malware Hit Thousands of GitHub Repos Through Stolen Accounts: How to Check Yours

A threat actor used 4,837 stolen GitHub accounts to probe 61,764 repositories for write access, starting on November 10. In at least 1,835 of those repositories, a credential-stealing script ran and sent secrets to the attacker. Application security company Aikido Security first reported the wfx-loot campaign and published the figures. Many owners have likely not…

wfx-loot malware probe pull request in a GitHub repository, a GitHub Actions secret stealer spread through stolen GitHub accounts

A threat actor used 4,837 stolen GitHub accounts to probe 61,764 repositories for write access, starting on November 10. In at least 1,835 of those repositories, a credential-stealing script ran and sent secrets to the attacker. Application security company Aikido Security first reported the wfx-loot campaign and published the figures.

Many owners have likely not noticed yet. Aikido found that 92% of the probe pull requests were still open. The attacker also deleted workflow runs and logs within about a minute, so a normal look at a project may show nothing wrong.

The name combines “wfx,” the malware author’s label for the tool, with “loot,” a term for stolen secrets. BleepingComputer reported that some hijacked accounts belonged to Fortune 100 organizations, the US General Services Administration, the French government, Nextcloud and WebdriverIO. A hijacked account on that list does not by itself show that the organization’s internal data leaked.

What changes for you

The risk depends on how you touch the affected code. Three groups need to act.

Repository owners and maintainers

Any account with write access to your repository could have been used against it. Aikido says a successful probe alone means the account is compromised, even if the payload never ran. Both Aikido and BleepingComputer advise one rule if the payload did run. Treat every secret and cloud role available to your workflows as stolen, and rotate them.

GitGuardian’s analysis of wfx-loot sets a wider scope. It says to rotate every secret the job could reach, not only the ones a workflow references.

Developers who ran npm install

One version of the attack hid inside an npm install hook. GitGuardian warns that developers who ran npm install on an affected repository could have run the payload on their own machines. That window lasted until cleanup commits removed it. SafeDep’s research says to treat any such machine as compromised and rotate its keys.

People who use affected packages

Automated publishing carried the payload into a few packages. The list includes Packagist package digitalelvis/neuronai-studio version 3.14.3. It also includes the Go module github.com/onuragtas/docker-env versions v1.0.278 and v1.0.280.

The researchers disagree on how risky these are. SafeDep says a normal composer require or go get does not trigger the payload. In neuronai-studio, the code runs only if someone runs npm install or npm ci inside the vendor directory. SafeDep advises pinning version 3.14.2 or earlier. Aikido takes a stricter line and says to treat any machine that installed or opened that version as compromised.

For the Go module, Aikido says the payload sits only in a GitHub Actions workflow file. The Go source and binaries did not change, so consumers may be unaffected. Aikido still recommends removing those versions. SafeDep also lists v1.0.282 and the related onuragtas/redock project, and it advises blocking all three versions. It flags one more Go case, a pseudo-version of github.com/vkuznet/gocurl.

SafeDep also found 28 WebdriverIO repositories that received commits from the bot account wdio-bot. No package release was affected, but SafeDep says the bot’s token should be treated as stolen.

How the attack worked

The attack ran in three steps on each repository. First, the attacker opened a harmless-looking pull request titled “docs: dependency audit notes” from a branch named wfx-docs. This only tested whether the stolen token could write to the repository.

Next, the attacker pushed the stealer. Aikido describes a heavily commented shell script of about 1,500 lines. The final step was cleanup. The attacker reverted the change and deleted the workflow run and its logs. Aikido says a missing run number in the workflow history is often the only trace left.

SafeDep counted how often each delivery method appeared:

Method Commit message What it changes Repos (SafeDep)
Workflow injection ci: refresh build cache Adds steps to an existing GitHub Actions workflow 7,309
npm install hook chore: add ci helper Adds a hidden .ci-xxxxxx.sh script run by postinstall in package.json 771
New workflow chore: add dependency audit workflow Adds a new build-audit workflow file 16

GitGuardian found a fourth form. The attacker appended code to existing shell scripts, such as start.sh or deploy.sh, that a workflow already calls.

How the npm hook got around GitHub’s hold

GitGuardian saw that payloads which changed workflow files were held. All seven visible November runs of that kind showed an “action_required” status and never executed.

The npm hook avoided this because it changes no workflow file. Existing trusted workflows ran npm install and executed the hidden script on their own. GitGuardian sampled 30 such repositories and found none blocked. Public logs from 19 repositories showed the script running, and 18 of them reported successful theft.

The attacker then shifted toward the hook. GitGuardian counted 10 to 70 hook commits per three-hour window at first. That figure peaked at 838 in one window on November 11 and 1,210 in one window on November 12.

What the stealer takes and how it stays in

This section covers the technical details. The script collects GitHub Actions secrets and variables, the job’s GITHUB_TOKEN, and OIDC and Actions runtime tokens. It also grabs AWS, Azure and Google Cloud credentials, plus SSH, GPG, Docker, Kubernetes, npm, PyPI, Vault and Terraform credentials.

AI tools are a clear target too. Aikido lists keys for OpenAI, Anthropic, Gemini, Hugging Face, Cursor, Copilot and Codex, among others. The script also scans the memory of runner processes for tokens. It copies .env files, shell histories, the last 100 commits and recent workflow artifacts.

Where permissions allow, it also moves into cloud accounts. Some of these steps aim to keep access after passwords and tokens change:

  • AWS: It creates long-lived access keys for IAM users. Aikido says it can rewrite a role’s trust policy so any AWS account can use it.
  • Azure: It adds federated identity credentials named wfx-ci- to Azure app registrations. SafeDep says workflows on the repository’s main branch can then sign in as that app, even after client secrets are rotated.
  • Google Cloud: It impersonates service accounts with collected credentials.
  • Vault and Kubernetes: It replays OIDC tokens against HashiCorp Vault and Kubernetes API servers.

Aikido says the script also posts fake “success” status checks to get past branch protection rules. SafeDep reports that this code exists but was not turned on in any sample it analyzed.

Stolen data goes out as a compressed archive. Aikido saw HTTP uploads to two attacker servers. GitGuardian reports that a version that appeared on November 12 switched to Telegram as its main channel, using five bot tokens. In a SafeDep sample of 200 payload commits, about a fifth used Telegram only. Aikido adds that newer versions contain Indonesian-language comments.

Timeline of the campaign

  • October 24 to 29: GitGuardian traced an early test phase with 80 payload commits from seven accounts in 12 repositories.
  • November 10, 12:45 UTC: The mass wave began, according to Aikido and GitGuardian.
  • November 11, 05:02 UTC: A second attacker server started receiving data, per GitGuardian.
  • November 12, 01:07 UTC: A new version added Telegram delivery.
  • November 12: GitGuardian and SafeDep both said the campaign was still active.

Why the numbers differ between reports

Each team counted in a different way, so the totals do not match. SafeDep found malicious commits in 8,093 repositories. Its search covered only default branches of public repositories, so it says the real total is likely higher. GitGuardian counted 28,500 payload patches from 2,367 accounts across 17,715 repositories.

The probe counts vary too. Aikido found 61,839 probe pull requests, while GitGuardian’s November 12 search returned 66,001. Script size estimates differ as well: about 1,500 lines per Aikido, and about 1,310 lines for the newest version per GitGuardian. Aikido also notes that deleted run logs mean the real number of successful thefts is likely above 1,835. None of these figures means the payload ran in every listed project.

A link to GhostAction

Aikido found that accounts hit by GhostAction activity in October were significantly more likely to be hit again. In more than 100 repositories, wfx-loot was injected into GhostAction workflow files. GitGuardian counted 431 wfx accounts, about 20%, that GhostAction had already compromised. It warns that some of those repositories still run GhostAction’s security-audit.yml workflow, which may still send secrets to GhostAction’s server.

Even so, Aikido believes different actors run the two campaigns, based on different servers, tools and methods. GitGuardian says the overlap does not prove a single actor, because leaked tokens are traded and reused.

How to check whether your repositories were hit

  1. Look for a wfx-docs branch and a pull request titled “docs: dependency audit notes.” Close the pull request and delete the branch.
  2. Search your history for these commit messages: “ci: refresh build cache,” “chore: add ci helper,” “chore: add dependency audit workflow,” “ci: restore” and “ci: cleanup.”
  3. Check for gaps in your GitHub Actions run numbers. GitGuardian notes that a gap shows a run was created, not that it executed.
  4. Look in package.json for a postinstall entry that calls a .ci- script. Check whether npm, pnpm or yarn ran on those commits without the –ignore-scripts flag.
  5. Revoke the hijacked account’s personal access tokens, OAuth and GitHub App grants, SSH keys and sessions. SafeDep also advises turning on two-factor authentication.
  6. Rotate every secret and variable the repository could read, including organization and environment secrets.
  7. Review cloud logs. In AWS CloudTrail, look for wfx- session names followed by new access keys or trust policy changes. In Microsoft Entra ID, look for wfx-ci- federated credentials you did not create.
  8. Rebuild any package version published between the malicious commit and the cleanup commit, starting from a clean commit.

Aikido warns that a missing wfx-loot artifact or cache entry does not mean nothing was taken. The missing run number is the more reliable sign.

What remains unclear

None of the reports includes a statement from GitHub. The researchers also do not say where the stolen GitHub credentials first came from. Aikido found settings built for private repositories, which suggests the payload may have run in private projects too. Those cases would not show up in public searches, so the full list of victims is still unknown.

About the Author

Trang Nguyen Avatar

Leave a Reply

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