CriticalSupply chainMonitoring

GhostAction returns: fake “Security Audit” workflows steal Actions secrets and mine git history for old credentials

Stolen GitHub accounts committed security-audit.yml or github_actions_security.yml to thousands of repos. Search all branches and forks, then rotate.

Published
Updated
Exploitation
Yes. GitGuardian counted 336 completed runs that exfiltrated secrets; StepSecurity confirmed a C2 reply from an uber/athenadriver run

What happened

GhostAction is a credential-theft campaign that logs in as real maintainers, commits a workflow dressed up as security tooling, and lets GitHub Actions hand over the secrets. StepSecurity first reported it in September 2025, when it took 3,325 secrets from 817 repositories (The Hacker News). It came back in 2026:

  • 31 August to 30 September 2026: GitGuardian counted the workflow in 772 public repositories of 373 users and organisations, targeting 2,577 secrets. The 7 September variant was called security-check.yml (GitGuardian).
  • 8 October 2026: two high-profile accounts were used. kitao, author of the pyxel game engine, pushed the workflow to 27 repositories between 13:20 and 13:44 UTC. henrywoo pushed it to 318 repositories (39 source repositories and 279 forks) between 21:10 and 21:26 UTC, ending with Uber’s uber/athenadriver, where he still had write access. That commit went straight to master with no review (StepSecurity).
  • 8 to 12 October: GitGuardian counted more than 30,000 repositories, about 3,000 users and organisations and about 1,900 compromised accounts. Socket reported more than 500 accounts committing the workflow to “tens of thousands” of repositories since 7 October (GitGuardian; Socket).
  • From 9 October: GitHub began blocking the malicious workflow from running, so the 10 and 12 October waves extracted no secrets. Across 3,669 runs in 605 repositories, GitGuardian found 336 that completed and exfiltrated 26 secrets from 13 repositories (GitGuardian).

StepSecurity thinks the accounts were most likely taken with personal access tokens leaked through infostealer logs or credential dumps (The Hacker News). As of the reporting, no malicious package releases had been published with the stolen publishing tokens (Socket).

What the workflow does

Details from StepSecurity and Socket.

  • Triggers: workflow_dispatch and push with no branch or path filter, so a push to any branch runs it.
  • Named secrets: before committing, the attacker reads your existing workflows and writes your secret names into the payload. In kitao/pyxel that meant CARGO_REGISTRY_TOKEN, PERSONAL_ACCESS_TOKEN, PYPI_PASSWORD and PYPI_USERNAME.
  • History mining (new in October, security-audit.yml): it checks out with fetch-depth: 0, then greps the working tree and git log -p --all for 13 credential patterns: AWS (AKIA, ASIA, secret keys, session tokens), Anthropic (sk-ant-), OpenAI (sk-proj-), OpenRouter (sk-or-), GitHub (ghp_, github_pat_), GitLab (glpat-), Google (AIza), Slack (xox[baprs]-) and SendGrid (SG.). Credentials you deleted years ago are in scope.
  • Exfiltration: one plain-HTTP POST to 193.32.204.199 on port 80 or 3000. The URL marker /?c=monami means named secrets were found; /?c=new means only history matches. The body contains REPO= and, around AWS keys, AKIA_CTX_START and AKIA_CTX_END.

Workflow and job names: “Security Audit” with job audit, and “Github Actions Security” with job send-secrets and a step called “Prepare Cache Busting”. Commit messages include “Add security audit workflow”, “Update security audit workflow”, “Add Github Actions Security workflow”, “Update Github Actions Security workflow”, “Add security check workflow” and “Trigger security scan” (StepSecurity).

Am I affected?

Check every branch, not just the default one:

bash
git fetch --all --quiet
for b in $(git for-each-ref --format='%(refname:short)' refs/remotes); do
  git ls-tree -r --name-only "$b" -- .github/workflows/ \
    | grep -E 'security-audit\.yml|github_actions_security\.yml|security-check\.yml' \
    | sed "s|^|$b: |"
done

Search history for the injection commits and the payload markers:

bash
git log --all --since=2026-08-31 --format='%h %an <%ae> %ad %s' \
  | grep -iE 'security audit workflow|Github Actions Security workflow|security check workflow|Trigger security scan'
git log --all -p --since=2026-08-31 -- .github/workflows/ | grep -nE '193\.32\.204\.199|AKIA_CTX_START|c=monami' | head

Across an organisation, StepSecurity suggests GitHub code search for "AKIA_CTX_START", "c=monami" and "193.32.204.199" with path:.github/workflows and org:your-org (StepSecurity). Then list runs of the fake workflows:

bash
gh run list --workflow security-audit.yml --limit 100
gh run list --workflow github_actions_security.yml --limit 100

Treat any completed run as confirmed exfiltration. Search proxy, firewall and runner logs for 193.32.204.199 on ports 80 and 3000. Older GhostAction infrastructure was 170.39.218.2, 45.139.104.115 and *.oast.fun (GitGuardian).

What to do now

  1. Revoke the committing credential first. Find the PAT, session or SSH key used to push the workflow, revoke it, and treat the account as fully compromised: sessions, PATs, OAuth grants and SSH keys (Socket). Rotating secrets alone leaves the way in open.
  2. Rotate the named secrets. Every secret whose name appears in the injected file. For publishing tokens (PyPI, npm, crates.io, registries), also review release history for versions you did not build (Socket).
  3. Rotate everything in history. Scan the full history, not just HEAD, for the 13 patterns above and rotate every hit, even ones deleted long ago. For AWS keys, review CloudTrail for new IAM users, new access keys and unusual regions (Socket).
  4. Delete the workflow from every branch and revert any edit to existing workflows. It runs on a push to any branch (StepSecurity).
  5. Check forks before enabling Actions on them. The 279 henrywoo forks each carry the file, and enabling Actions on such a fork runs it with your context (StepSecurity).
  6. Require approval for workflow runs and protect .github/workflows/. In typecho-fans/plugins, re-trigger runs stalled at action_required because the repository required approval, so nothing left. StepSecurity calls this the single control that stopped exfiltration in this wave (StepSecurity).

Why this matters

This variant does not need you to have secrets in GitHub Actions at all. It reads your entire git history. A key committed and deleted in 2019 is as exposed as one in today’s .env.

Sources