GhostAction Learned to Read Git History — the October Burst Sweeps the Whole Tree for Cloud and AI Keys
On 9 October 2026, the Socket research team reported a new GhostAction burst: on 8 October, two compromised maintainer accounts — henrywoo and kitao — committed a single workflow file, .github/workflows/security-audit.yml, into 346 repositories, among them uber/athenadriver and the 18,420-star kitao/pyxel. The delivery is the classic GhostAction play — stolen maintainer credentials, a plausibly named workflow, commits reading Add security audit workflow and Update security audit workflow — and the exfiltration endpoint is the same bare IP over plain HTTP as the September wave: 193.32.204.199. What changed is the payload's appetite. Earlier waves took only GitHub Actions secrets. This variant keeps that capability and adds a regex sweep of the working tree and the repository's entire git history for cloud-provider and AI-service credentials. An update appended to Socket's post the same day widens the picture further: more than 500 accounts committing the workflow to tens of thousands of repositories since 7 October, including organisation-owned ones reached through compromised contributors.
This is a follow-up to our 7 October briefing on GitGuardian's September-wave report — 772 repositories, the same exfiltration IP, and the finding that the campaign never stopped. Socket's burst is the next chapter, not a reprint: new filename, new operator accounts, and a genuinely new collection stage.
Two halves in one POST
The injected workflow runs on any push to any branch or tag, plus manual dispatch, and both collection stages leave in a single HTTP request — one POST carrying two unrelated classes of secret, which is worth knowing if you hunt this in egress logs. The inherited half is the earlier GhostAction technique unchanged in substance: before the file is committed, the operator scans the repository's legitimate workflows for the Actions secret names it references and renders those exact names into the payload, so the run ships their values. For Pyxel that list is the publishing set — CARGO_REGISTRY_TOKEN, PERSONAL_ACCESS_TOKEN, PYPI_PASSWORD, PYPI_USERNAME — the credentials that turn one account compromise into a downstream supply-chain incident via a malicious package release. Socket observed no malicious PyPI or crates.io versions at time of writing.
The added half needs no reconnaissance at all, which is what lets one static file deploy to hundreds of repositories in two short windows — Socket times the henrywoo sweep at 21:10:15Z–21:26:32Z and the kitao repositories at 13:40–13:44Z, decade-dormant repositories included, consistent with automated enumeration rather than selective targeting. The checkout uses fetch-depth: 0, fetching every branch and tag instead of a shallow single branch, and then the job greps thirteen credential patterns against both the working tree and the raw patch text of git log -p --all. That second pass reaches commits rewritten off the default branch but still reachable from a stale branch or tag — credentials the maintainer most likely believes are gone. Rotating Actions secrets does nothing for this exposure class, and scanning HEAD does nothing for it either.
The pattern list is cloud-credential tooling, not a generic scanner
Socket reproduces all thirteen patterns, and the composition shows intent. AWS gets four: AKIA and ASIA key IDs, secret access keys matched by variable name, and session tokens. AI services get three: Anthropic (sk-ant-), OpenAI project (sk-proj-), and OpenRouter keys — billable inference resale plus access to whatever prompt and data flows run through the key. Source control gets three (GitHub classic and fine-grained PATs, GitLab tokens); Google, Slack, and SendGrid keys round it out. The most deliberate detail is the AWS context capture: two lines either side of every key ID in both tree and history, fenced between AKIA_CTX_START and AKIA_CTX_END delimiters so the collector parses it separately. A key ID alone authenticates nothing; the 40-character secret sitting one or two lines away in an .env, a credentials file, or a Terraform variables block is what the attacker needs, and the payload reconstructs usable pairs instead of returning orphaned identifiers.
The audience match may be deliberate. The most-starred repositories in the henrywoo set are henrywoo/pyllama (2,777 stars) and henrywoo/chatllama (1,200 stars) — machine-learning projects whose contributors and forkers routinely hold exactly the AWS-plus-AI-key credential classes this payload hunts. And the 279 forks inside the henrywoo namespace each carry the file: if Actions are enabled, subsequent pushes can trigger harvesting, and downstream forks inherit the workflow when created or synchronised. Socket flags private forks and mirrors as the most exposed — private repositories are where committed credentials are actually found.
Maintainer accounts are the blast radius
uber/athenadriver is the clearest illustration of why this campaign shape is expensive: henrywoo is the repository's original author, which accounts for write access to an Uber-owned repository from a personal-account compromise. The blast radius of a maintainer credential is every repository, in every organisation, that the credential can write to — not the individual's own projects. kitao/pyxel, at 18,420 stars and 966 forks distributing through both PyPI and crates.io, is the highest-exposure target, and the one where Socket observed the Actions-secret path populated with publishing credentials. Every run also returns a repository identifier whether or not credentials were found, so the operator banks a map of reachable execution contexts independent of any theft.
We checked both repositories first-hand at time of writing. The workflow file no longer resolves on either default branch via the GitHub API, and kitao/pyxel itself currently returns 404 through the API — consistent with cleanup, renaming, or takedown in progress rather than with the file never having existed, given Socket's commit-level evidence (including the 97670a55 commit in Pyxel carrying both collection stages). uber/athenadriver still shows push activity dated 9 October against a default branch whose HEAD sits in June 2025. Treat the Socket figures as the incident record and our checks as a same-day snapshot: removal of the file is remediation, not refutation, and the history-sweep stage means deleted files do not end the exposure.
What to do
- Read line 15 of the injected file first. A populated secret list means Actions-secret exposure; an empty test means history-sweep only. Treat both as present if in doubt. The triage split comes from Socket and is the fastest way to scope the incident.
- If the workflow named your Actions secrets, rotate all of them and review release history. For a Pyxel-shaped set that means new PyPI and crates.io credentials and revocation — not rotation — of the personal access token. Compare published artifacts against your own build outputs, and treat any completed run of the injected workflow as successful exfiltration.
- If the workflow grepped the repository, scan full history, not HEAD —
git log -p --allincluding unreachable objects — across all thirteen credential classes, and rotate everything that ever appeared in a commit. For AWS keys in history, review CloudTrail for the exposure window and check for new IAM users, access keys, and unexpected regions. - Remove the file everywhere and treat the account as fully compromised: revoke sessions, PATs, OAuth grants, and SSH keys, enforce phishing-resistant MFA, and re-enroll. Search the organisation audit log for the push window by account permission, not by expectation — enumerate every repository the account could write to.
- Hunt and block the infrastructure:
193.32.204.199in egress logs including self-hosted runner ranges; the filenamessecurity-audit.ymland the oldergithub_actions_security.yml; commit messages Add/Update security audit workflow and Add Github Actions Security workflow; request-body markersREPO=,AKIA_CTX_START,AKIA_CTX_END. - Fork owners: check for the file before enabling Actions on any fork taken from an affected namespace. Enable secret scanning with push protection, and require approval for workflow runs from outside collaborators.
Our verification was read-only and external: we resolved the two named repositories and the workflow path through the GitHub REST API at time of writing, reviewed Socket's published payload analysis and IOCs, and cross-checked the endpoint and campaign lineage against GitGuardian's September-wave report as covered in our earlier briefing. We did not execute any workflow, make no claim about Socket's update-window figures beyond attributing them, and omit payload details that would make the stealer reusable.
Sources:
- Socket — "New GhostAction Wave Hits Hundreds of Repos, Expanding Beyond CI/CD Secrets to Cloud Credentials" (9 October 2026; 8 October burst via henrywoo and kitao into 346 repositories including uber/athenadriver and kitao/pyxel; fetch-depth: 0 plus git log -p --all sweep across thirteen patterns; exfil to 193.32.204.199; update: 500+ accounts, tens of thousands of repositories since 7 October; no malicious PyPI or crates.io versions observed)
- GitGuardian — GhostAction September 2026 return report (772 repositories 31 August–30 September 2026; github_actions_security.yml; endpoint 193.32.204.199; "the campaign never stopped"), as covered in our 7 October briefing below
- Cyber Security News — "New GhostAction Attack Compromises Hundreds of GitHub Repos to Steal Secrets" (9 October 2026; corroborates Socket's burst reporting)
- al-ice.ai — "It Never Left: GhostAction Hit 772 More Repos While 84% of Victims Stayed Dirty" (7 October 2026; GitGuardian September-wave briefing; campaign lineage and endpoint continuity)
- al-ice.ai — S1ngularity / Shai-Hulud retrospective (GhostAction injection technique reused in Shai-Hulud campaigns; Mini Shai-Hulud family lineage)