Skip to content
T threat.cafe

· Solene Beaumont-Adjei (editorial persona) · Incident response · on threat.cafe

Security audit workflows that steal your AI keys: GhostAction's October wave and a 10-minute repo check

Yes, check today. From 7 October 2026, stolen maintainer credentials pushed workflows named security-audit.yml or github_actions_security.yml into GitHub repositories. Socket counted more than 500 accounts by 9 October. The workflows search CI secrets and full git history for Anthropic, OpenAI and OpenRouter keys, AWS keys and GitHub tokens. GitHub started blocking them on 9 October. Secrets sent before then are still out. Search every branch back to 31 August, then revoke and rotate.

Cold open: two sweeps on 8 October

Two maintainer accounts did the damage on 8 October 2026, and neither maintainer pushed anything. At 13:20 UTC, the account of kitao started committing a workflow called "Security Audit". The account belongs to Takashi Kitao, author of the pyxel game engine. It hit 27 repositories in 24 minutes. Someone re-ran the pyxel workflow by hand at 13:36:32 and again at 13:42:35.

About eight hours later, the henrywoo account woke up. Henry Wu was the original author of Uber's athenadriver. Between 21:10 and 21:26 UTC, his account pushed the same file to 318 repositories. That was 39 source repositories and 279 forks. The athenadriver commit landed at 21:25:54. Its run got a reply from the attacker's server about four seconds after it started.

Rohan Prabhu at StepSecurity reconstructed those minutes. The workflow looked like housekeeping. It was not.

What the workflow took

The GhostAction workflow, as StepSecurity and the Socket Research Team describe it, collected secrets in two passes and sent them out over plain HTTP. The first pass took repository Actions secrets that the attacker had named in advance. For pyxel, those were publishing credentials for PyPI and crates.io, plus a personal access token.

The second pass is new in this wave. The job checked out the full git history. It then searched the tree and every past commit for 13 credential patterns. Socket lists them: AWS key IDs, secret keys and session tokens; Anthropic, OpenAI project and OpenRouter keys; GitHub classic and fine-grained tokens; GitLab tokens; Google and Firebase keys; Slack tokens; SendGrid keys. A key deleted from a .env file two years ago still counted.

Everything left in a single POST to 193.32.204[.]199. No DNS lookup happened. Domain-based egress rules saw nothing.

CI is where AI keys pile up. Evaluation jobs, review bots and agent runners all need a model key somewhere. This workflow went straight for them.

The messy middle: what maintainers found when they looked

The cleanup phase, not the push, is where GhostAction did most of its harm, because the campaign had run for weeks before anyone counted. GitGuardian's Gaetan Ferry and Guillaume Valadon published their tally on 7 October. Between 31 August and 30 September 2026, the workflow reached 772 public repositories owned by 373 users and organisations. It targeted 2,577 secrets. By 5 October, only 124 of those 772 repositories (16%) had cleaned it out of their visible public history.

That number tells the real story. Most affected repositories still carried the file.

StepSecurity found the attacker's server active as early as 4-5 September. So the October wave was not a fresh start. It was the same operation, scaled up.

Then the count grew fast. Socket reported 346 repositories on 8 October. By its 9 October update, Socket had counted more than 500 accounts and tens of thousands of repositories since 7 October. Some were organisation repositories, reached through a single compromised contributor. GitGuardian's 13 October update put the 8-12 October wave at more than 30,000 repositories, about 3,000 users and organisations, and about 1,900 compromised accounts.

Forks made it worse. Socket found that "the 279 forks in the henrywoo namespace each carry the workflow file." A fork can pick up the file when it syncs with an infected upstream. Socket's warning was blunt: "Private forks and downstream mirrors are the most exposed."

Code search helped, but only partly. On 9 October, StepSecurity found 378 repositories with a live malicious workflow on the default branch. The history-mining marker showed up in 182 of them. The named-secrets marker showed up in 88. StepSecurity calls those counts approximate. Code search only sees default branches. A maintainer who checked main and stopped there could miss a copy on a feature branch.

One maintainer team did block it in time. On 7 October, the xxyangyoulin account pushed an empty commit and a README edit to typecho-fans/plugins. The goal was to re-trigger the workflow. A required approval for workflow runs held the runs. StepSecurity credits that gate with stopping exfiltration there. Nobody wrote new code to stop it. A settings box did the work.

GitHub stepped in on 9 October. GitGuardian reports that GitHub began blocking the malicious workflow from running that day. The 10 and 12 October waves extracted no secrets. Across the runs GitGuardian collected, 499 of 3,669 executed, mostly because GitHub held the rest for approval. 336 completed, sending out 26 secrets from 13 repositories.

That sounds small. It is not the whole picture. As of 9 October, StepSecurity had seen no malicious package releases made with the stolen publishing tokens. Its caution still applies. An absence of observed abuse is not evidence that the credentials are secure.

The timeline

The threat.cafe GhostAction October Timeline below pulls the dated events from StepSecurity, Socket and GitGuardian into one strip.

threat.cafe GhostAction October Timeline (UTC, sources: StepSecurity,
Socket, GitGuardian; counts are each vendor's own)
------------------------------------------------------------------
Sep 2025      First GhostAction wave: 817 repos, 327 users,
              3,325+ secrets (GitGuardian)
31 Aug-30 Sep 772 public repos, 373 users/orgs, 2,577 secrets
2026          targeted (GitGuardian)
4-5 Sep       Current exfil server first observed (StepSecurity)
5 Oct         124 of 772 repos (16%) cleaned (GitGuardian)
7 Oct         xxyangyoulin re-trigger at typecho-fans/plugins;
              approval gate holds the runs (StepSecurity)
8 Oct 13:20-  kitao sweep: 27 repos incl. pyxel (StepSecurity)
      13:44
8 Oct 21:10-  henrywoo sweep: 318 repos = 39 source + 279 forks,
      21:26   incl. uber/athenadriver (StepSecurity, Socket)
9 Oct         GitHub begins blocking the workflow (GitGuardian)
9 Oct         Socket: 500+ accounts, tens of thousands of repos
              since 7 Oct
8-12 Oct      30,000+ repos, ~3,000 users/orgs (GitGuardian)
10, 12 Oct    Later waves extract no secrets (GitGuardian)
------------------------------------------------------------------
Search back to: 31 Aug 2026. File names: security-audit.yml,
github_actions_security.yml, security-check.yml

The steel-man: GitHub is blocking it, so it is over

The strongest counterargument says GitHub fixed this on 9 October, so teams can stand down. The facts cut against it. Runs that finished before 9 October already sent their secrets. Credentials in git history stay readable until you rotate them. GitGuardian also linked 13 victim repositories to at least four separate cryptomining campaigns. Its reading is that stolen GitHub credentials get traded and reused. A blocked workflow does not revoke a stolen token. Only you can do that.

The 10-minute repo check

The threat.cafe 10-Minute Repo Check below is read-only and runs with the GitHub CLI. Replace YOUR_ORG. Treat any completed run as confirmed exfiltration, as StepSecurity and Socket advise.

# 1. Default branches: file names and indicator
for f in security-audit.yml github_actions_security.yml security-check.yml; do
  gh search code --owner YOUR_ORG --filename "$f" --json repository,path \
    --jq '.[] | "\(.repository.nameWithOwner)\t\(.path)"'
done
gh search code --owner YOUR_ORG "193.32.204.199" --json repository,path \
  --jq '.[] | "\(.repository.nameWithOwner)\t\(.path)"'

# 2. Registered workflows per repo, including ones run from other branches
gh repo list YOUR_ORG --limit 2000 --json nameWithOwner --jq '.[].nameWithOwner' |
while read -r r; do
  gh api "repos/$r/actions/workflows" --paginate \
    --jq ".workflows[] | select(.path | test(\"security-audit|github_actions_security|security-check\")) | \"$r\t\(.path)\t\(.state)\t\(.created_at)\""
done

# 3. Every branch and tag in a local clone, since 31 August
git fetch --all --tags --quiet
git log --all --since=2026-08-31 --diff-filter=A --name-only --format='%h %an %ad' -- \
  .github/workflows/security-audit.yml \
  .github/workflows/github_actions_security.yml \
  .github/workflows/security-check.yml

# 4. Runs of a found workflow
gh run list --repo OWNER/REPO --workflow security-audit.yml --limit 100

On Enterprise plans, also review the audit log. Look for workflow files added straight to default branches without a pull request.

If you find it

The response order matters, and GitGuardian's advice sets it. Revoke first, because rotating secrets alone is not enough when "someone else will use it again."

  1. Revoke the credential that pushed the workflow. Revoke the account's sessions, tokens, OAuth grants and SSH keys.
  2. Rotate every Actions secret, and every credential that ever appeared in any commit on any branch. Rotate AI keys at the issuer: Anthropic, OpenAI, OpenRouter. Check their usage for the exposure window.
  3. For AWS keys found in history, review CloudTrail for new IAM users, new access keys and unusual regions, as Socket recommends.
  4. Remove the workflow from every branch. Revert the commit.
  5. Check forks and mirrors, private ones first.
  6. Hold releases. Review PyPI, npm and crates.io histories for versions you did not publish.

Keep a rotation spreadsheet. Give each secret one row, with owner, issuer and rotated time.

Prevention that would have helped

The controls that would have stopped this wave are mostly GitHub settings, not new tools.

  • Require approval for workflow runs. It stopped the typecho-fans attempt.
  • Put .github/workflows/ in CODEOWNERS and require code-owner review through a branch ruleset.
  • Use fine-grained, short-lived tokens instead of classic PATs.
  • Allowlist egress on runners. See our post on egress allowlisting for coding agents and CI runners.
  • Use OIDC for cloud access instead of static keys.
  • Turn on secret scanning with push protection.
  • Set spend caps and usage alerts on every AI key.

What to tell the people who sign off

Each sign-off group needs one line, and each line below rests on the sources above.

  • Finance: the main cost is engineer time to rotate keys, and AI keys without spend caps have no billing ceiling if stolen.
  • Security lead: the blast radius is every Actions secret the workflow named plus every credential ever committed to any branch.
  • Legal and compliance: export workflow run logs and audit log entries before you delete anything; they show what ran and when.
  • Operations: the check takes minutes per organisation; rollback is a revert of one workflow file per branch.

Where this would be wrong

The urgency here rests on assumptions that may not hold for you. Suppose your organisation requires approval for every workflow run. If no injected run completed, your exposure is the pushing token, not your secrets. If your history holds no committed keys, the history pass found nothing. If GitHub's block covers every variant, new waves stop. None of that changes what left before 9 October.

What we don't know yet

The open questions are about scale and attribution, not mechanism. The Hacker News calls leaked tokens from infostealer logs the most likely entry point. That is unconfirmed. Nobody has published how many AI keys actually left. Socket and GitGuardian count differently, so their October figures may not overlap. The operator is unknown.

The threat.cafe board records these workflow file names and the indicator, so you can check them in hooks and gateways.

Volatility: VOLATILE (event-triggered review). Review when GitHub, StepSecurity, Socket or GitGuardian publish a new wave, new file names or new indicators.

Sources

#github-actions #ghostaction #ci-secrets #ai-api-keys #incident-runbook

All posts