SUPPLY CHAIN

4,837 Hijacked GitHub Accounts Planted a CI Secret Stealer in 1,806+ Repositories

Starting November 10, an attacker used 4,837 stolen GitHub accounts to probe 61,764 repositories and run a CI secret stealer in at least 1,806 of them.

Matt Lucas  |  November 12, 2026  |  6 min
Editorial hero illustration
4,837
Hijacked GitHub accounts
61,764
Repos hit with test PRs
8,093
Repos with malicious commits
1,806+
Repos where stealer ran
TL;DR
  • What: An attacker used stolen credentials for 4,837 GitHub accounts to push a CI secret stealer into repositories those accounts could write to, starting Tuesday, November 10, 2026.
  • Impact: The stealer ran in at least 1,806 repositories, took every secret, token and cloud credential the workflows could reach, and can leave AWS and Azure backdoors that survive token rotation.
  • Fix / mitigation: Aikido Security and SafeDep advise treating every secret and cloud role available to affected workflows as compromised, revoking the commit author's tokens, OAuth grants, SSH keys and sessions, enabling 2FA, and hunting for wfx-prefixed cloud identities.
  • Who's at risk: Any organization whose GitHub repositories grant write access to outside collaborators or org members, especially those using GitHub OIDC federation into AWS, GCP, Azure or Vault, or self-hosted runners.

An attacker holding stolen credentials for 4,837 GitHub accounts spent roughly 40 hours pushing a CI secret stealer into every repository those accounts could write to. Aikido Security counts at least 1,806 repositories where the stealer executed and likely sent out credentials. SafeDep counted 8,093 repositories that received malicious commits between 12:46 UTC on Tuesday, November 10 and 04:36 UTC on Thursday, November 12, and that count covers only the default branches of public repositories. The real number is higher, and new test pull requests were still appearing at 05:38 UTC Thursday.

This is not a poisoned package waiting for downloads. The attacker went straight to the CI layer, where secrets, cloud roles and publishing rights sit together, and built a payload that turns one workflow run into persistent cloud access.

How the Campaign Worked

Each intrusion began with a probe. The attacker opened a pull request titled "docs: dependency audit notes" from a branch named wfx-docs to confirm the account had write access. These test pull requests reached 61,764 repositories. Of those, 10,431 were submitted through collaborator or organization access, which means the compromised accounts were reaching into repositories they did not own. When Aikido checked, 92% of those collaborator pull requests were still open.

Where the probe succeeded, the stealer followed. SafeDep found it delivered two ways. In 7,309 repositories it was injected into an existing workflow, typically via a commit labeled "ci: refresh build cache" that added about 1,500 lines. In 771 repositories it arrived as an npm postinstall hook pointing at a .ci-xxxxxx.sh script, which also executes on any developer machine that runs npm install against that commit. Other variants added a new build-audit workflow on a short-lived chore/ branch or seeded empty repositories with "chore: initial commit" before dropping a workflow file.

The attacker usually reverted the change within minutes, using commits such as "ci: restore" and "ci: cleanup". Where the stealer ran, its logs were deleted, and usually the workflow run itself. That cleanup is why Aikido says a missing run number on the attacker's commit is a more reliable sign of execution than the presence of wfx-loot artifacts, wfx- cache entries or WFX-BEGIN step summaries.

A test PR alone means the account is compromised

Aikido states that any account that opened one of the attacker's wfx-docs test pull requests is compromised, even if the stealer never ran. Its analysis does not explain how the attacker obtained the 4,837 credentials.

What the Stealer Takes

The payload is built to empty the runner. According to the researchers, it collects:

Exfiltration goes by HTTP POST to 194.150.166[.]244:8080/exfil, 18.143.168[.]96:8080/exfil or 153.75.82[.]159:8080, or to a Telegram chat. In a SafeDep sample of 200 payload commits, about a fifth used Telegram only, so network blocking on the three IPs will not catch every case. The stealer also carries settings for private repositories, which Aikido reads as a sign it is running there too, outside what any public search can count.

From CI Token to Persistent Cloud Access

The most damaging part of the payload runs after collection. The stealer exchanges GitHub OIDC tokens for live AWS, GCP and Azure sessions. On AWS it can create long-lived access keys for IAM users and rewrite a role's trust policy to open the role to any AWS account. In Azure it can add federated identity credentials prefixed wfx-ci- to Entra ID applications, which lets workflows in the compromised repository sign in to Azure without a stored secret.

Those steps are designed to survive credential rotation. Rotating GitHub secrets does not remove a rewritten trust policy, a new IAM access key or a rogue federated credential. Organizations that rotate and stop there may still be exposed.

Cloud persistence indicators reported by researchers

Entra ID federated credentials named wfx-ci-* that the owner did not create. AWS CloudTrail AssumeRoleWithWebIdentity or AssumeRole sessions named wfx-*, followed by CreateAccessKey or UpdateAssumeRolePolicy. GCP GenerateAccessToken and SignJwt calls from the GitHub workload identity pool. Vault JWT logins from the GitHub OIDC issuer.

Downstream Spread

Because the stealer runs inside CI, it also reaches whatever CI publishes. The researchers confirmed it reached at least one Packagist package and one Go module through automated publishing triggers. Any repository whose workflows publish on push or tag could have released a build that carries attacker changes, and the npm postinstall variant puts developer laptops in scope alongside runners.

Indicators of Compromise

Researcher Guidance and RedEye Assessment

Aikido's position is that in any repository where the stealer ran, every secret and cloud role available to its workflows is compromised. SafeDep advises affected owners to revoke the commit author's tokens, OAuth app grants, SSH keys and sessions, turn on 2FA, and rotate every secret and variable the repository can read. Machines that ran npm install on an affected commit are treated as compromised, with their keys rotated. In most repositories that received only a test pull request, nothing was pushed or the stealer was blocked by repository settings or account permissions, but the account behind the probe is still burned.

The figures here are a floor. They cover public repositories on default branches, the stealer has private repository settings, and the attacker was still opening pull requests after both research teams finished counting. The cloud persistence mechanisms mean the incident does not end at token rotation, and the wide use of collaborator access means an organization can be hit through an outside contributor's account it never directly controlled.

RedEye Security can assess GitHub organization exposure to this campaign, review OIDC trust relationships across AWS, Azure, GCP and Vault for wfx-prefixed persistence, and scope what left your runners. Contact RedEye for an assessment.

Questions about your exposure?

RedEye Security provides assessments for organizations that need to understand their real risk.

Talk to us