Why WFX-Loot matters to GitHub Actions users

A GitHub repository is not only source code. Its workflows may access package tokens, cloud credentials, deployment keys, environment variables, and identity tokens used to request short-lived cloud access. A compromised maintainer account can therefore become a production security incident.

Aikido's WFX-Loot investigation, checked on November 15, 2026, describes a campaign that began on November 10. Its report says 4,837 compromised GitHub accounts opened probe pull requests across 61,764 repositories. It also reports that 10,431 pull requests reached repositories through collaborator or organization access, and that 92% were still open in its snapshot.

The report gives different counts for payload executions in its summary and detailed sections, so this article avoids repeating a precise execution total. The practical point is clear: a probe can indicate a compromised contributor account, and a workflow run can expose much more than visible repository secrets.

Aikido's official WFX-Loot explainer video thumbnail
Thumbnail from Aikido's official WFX-Loot explainer. Source: Aikido investigation.

How the campaign moved

Aikido describes three stages:

  1. Probe: a compromised account opens a pull request titled docs: dependency audit notes from a branch named wfx-docs, confirming that its stolen token can write to the repository.
  2. Payload: the attacker adds code to an existing workflow, adds a shell helper and npm postinstall hook, or creates a temporary workflow on a randomly named chore branch.
  3. Cleanup: the changes are reverted quickly and the workflow run and logs are deleted. A missing run number can become a more reliable clue than an obvious malicious file.

The payload attempts to collect runner environment variables, GitHub Actions secrets and variables, the workflow token, OIDC tokens, credential files, shell histories, and keys for cloud, package, infrastructure, and AI services. It can also try to persist by creating long-lived AWS keys, weakening role trust policies, or adding Azure federated credentials. Rotating the original GitHub secret is not enough if a new cloud identity has already been created.

Indicators to search for

Search every repository where a compromised account had write access, including organization repositories and projects reached through collaborator permissions.

Aikido lists these indicators:

  • Branches named wfx-docs, chore/ followed by eight random characters, or ci-check- followed by four digits.
  • Pull request title docs: dependency audit notes.
  • Commit messages ci: refresh build cache, ci: restore, chore: add ci helper, ci: cleanup, or chore: add dependency audit workflow.
  • A temporary workflow named like build-audit-xxxxxxxx.yml.
  • A .ci-xxxxxx.sh helper and a new npm postinstall hook.

The absence of an artifact named wfx-loot, a cache entry beginning with wfx-, or a WFX marker in the step summary does not prove the repository is clean. The report says the workflow run itself was often deleted.

Audit pull requests with GitHub CLI

This checks all pull-request pages for the exact probe title in one repository. Use a GitHub CLI session that can read every relevant pull request:

OWNER="your-org" REPO="your-repo" gh api "repos/$OWNER/$REPO/pulls?state=all&per_page=100" --paginate \ --jq '.[] | select(.title == "docs: dependency audit notes") | [.number, .user.login, .head.ref, .created_at] | @tsv' 

Search local history for the reported commit messages and branch names:

git fetch --all --prune git log --all --since="2026-11-10T00:00:00Z" \ --format="%h %ad %s" --date=iso \ --grep="ci: refresh build cache\|ci: restore\|chore: add ci helper\|ci: cleanup\|chore: add dependency audit workflow" git branch -a | grep -E "wfx-docs|chore/[a-z0-9]{8}|ci-check-[0-9]{4}" 

These checks are useful, not exhaustive. A branch may have been deleted or a repository rewritten. For organization-wide coverage, use an organization owner or security administrator account and inspect repositories, audit logs, Actions history, and access grants centrally.

What to do if you find an indicator

If you find only the probe: investigate the account that opened it. Revoke its sessions and tokens, review OAuth grants and SSH keys, restore account access, and check every repository the account could write to. A probe is evidence of account compromise even if you cannot find a payload run.

If the payload ran: assume every secret and cloud role available to that workflow was exposed. Rotate GitHub and package-registry credentials, deploy keys, cloud credentials, and API tokens. Revoke active cloud sessions where possible. Inspect AWS access keys and role trust policies, Azure federated credentials, GCP service-account keys, Kubernetes credentials, and Vault policies. Rebuild affected self-hosted runners from trusted images rather than assuming a cleanup script is enough.

Also review automated package publishing jobs and any machine that installed a package version Aikido identified as affected. The report names a Packagist package and two Go module tags; follow its current advisory for exact versions and remediation.

Harden GitHub Actions after the audit

Start with least privilege. GitHub recommends explicitly limiting GITHUB_TOKEN permissions rather than relying on broad defaults.

name: CI on: pull_request: push: branches: [main] permissions: contents: read jobs: test: runs-on: ubuntu-latest permissions: contents: read steps: - uses: actions/checkout@<full-commit-sha> - run: npm ci - run: npm test 

Replace the placeholder with the verified full commit SHA for the action version you intend to use. Pin third-party actions to immutable SHAs and update them through reviewed dependency updates. Do not let untrusted pull-request code access production secrets. Keep deployment jobs separate, use protected environments, and require reviewers before a workflow can publish or deploy.

OIDC can remove long-lived cloud secrets from GitHub, but it is not a magic shield. A compromised workflow with permission to request an identity token may still try to exchange it. Restrict cloud trust to the intended repository, branch, environment, audience, and workflow. GitHub's current OIDC reference documents immutable subject claims for repositories created after July 15, 2026; update cloud trust conditions to match the subject format your repository actually uses.

Finally, isolate self-hosted runners and avoid sharing a runner between untrusted pull requests and production deployments. CI should receive only the credentials required for the current job, for the shortest time possible.

The takeaway

WFX-Loot is a reminder that the CI runner is part of your production security boundary. A small workflow edit can expose cloud roles, package publishing, AI provider keys, and infrastructure credentials. A clean working tree is not proof that workflow history is clean.

Audit every repository your account or organization can write to, then verify cloud trust relationships as carefully as GitHub secrets. Which part of your CI environment would be hardest to rebuild safely today: runner machines, cloud identities, or deployment credentials?

Sources and further reading

Author links: GitHub · LinkedIn · StackShade on YouTube

AI disclosure: This article was prepared by an autonomous AI editorial agent from public sources. Incident details and defensive commands were checked against primary reporting and official GitHub documentation; no repository scan was run in this article.