GhostAction hit 500 GitHub accounts: how to lock down Actions secrets
The campaign uses stolen maintainer logins to add a workflow called Security Audit, then sends out every cloud, AI and registry key it can find, including keys deleted from the code long ago.
James Harrison / UnsplashOn October 8, someone logged in as two well-known open source maintainers and, in two short bursts, added a new file to 345 GitHub repositories. The file was a GitHub Actions workflow named "Security Audit." It did no auditing. It collected the secrets each repository used in its build pipeline, searched the full git history for cloud, AI and code-hosting keys, and sent the lot to a server at a bare IP address.
The campaign is called GhostAction, and it is the second time it has hit GitHub in about a year. By October 9 Socket, a software supply chain security company, had found more than 500 accounts that had pushed the same workflow, starting October 7, into tens of thousands of repositories, some of them owned by companies. Any business that builds software on GitHub, or uses open source packages built there, should treat this as a check on how its own pipelines handle secrets.
What happened on October 8
StepSecurity, which sells security tooling for GitHub Actions, published a timeline on October 9. At 13:20 UTC the account of Takashi Kitao, who maintains the pyxel game engine, began pushing the workflow to 27 of his repositories. About eight hours later, between 21:10 and 21:26 UTC, the account of Henry Wu pushed it to 318 repositories: 39 originals and 279 forks. One of them was uber/athenadriver, an Uber-owned project Wu wrote and still has write access to. That one detail shows the risk for companies: a single contributor's stolen login reaches every organization that has given that person write access.
How the attacker got in is not confirmed. StepSecurity and The Hacker News point to a personal access token, a long-lived GitHub password for scripts, leaked through infostealer malware logs or an old credential dump. The Cloud Security Alliance, in a research note on October 11, calls that an inference. Attribution is open, and the counts from different researchers do not agree.
GitGuardian, which tracked the first wave in September 2025, counted 817 repositories across 327 users and 3,325 stolen secrets then. For August 31 to September 30 this year it counted 772 public repositories and 2,577 targeted secrets, according to The Hacker News. Socket said it had seen no malicious package releases as of October 9.
How the workflow works
The workflow file is named security-audit.yml or github_actions_security.yml. It runs on any push to any branch or tag, and anyone with write access can start it by hand. It does two things.
First, it reads the repository's other workflow files to learn the names of the secrets they use, then pulls those secrets into its own job. For pyxel those were the tokens for publishing to PyPI and crates.io, the Python and Rust package registries, and a secret named PERSONAL_ACCESS_TOKEN.
Second, it checks out every branch and tag with full history and runs a search across every commit ever made. It looks for 13 kinds of credential: AWS access keys and session tokens, Anthropic, OpenAI and OpenRouter API keys, GitHub and GitLab tokens, Google and Firebase keys, Slack tokens and SendGrid keys. A key someone committed in 2021 and deleted the next day is still in the history, so it is still found.
Everything goes out in one plain HTTP request to 193.32.204.199. Because the address is a raw IP, no DNS lookup happens, so filters that block bad domain names do not see it. Every run also reports the repository name, even when it finds nothing, so the attacker builds a list of where its code can run.
Why this matters to companies
Most companies do not maintain a popular open source project, but almost all of them have the same weak points GhostAction uses.
The first is tokens tied to people. A developer's personal access token often has write access to dozens of company repositories and lasts for months or has no expiry. One leaked token is enough.
The second is workflow files that nobody reviews. If anyone with write access can add a file under .github/workflows to the default branch, they can run code that reads every secret the repository holds.
The third is long-lived cloud keys in CI. A stored AWS key pair in GitHub secrets works from any machine on the internet until someone rotates it.
The fourth is secrets left in history. Deleting a committed key from the current code does nothing. It has to be revoked.
The fifth is open egress from build runners. Machines that can send traffic anywhere make theft easy, and self-hosted runners sit inside the company network.
The good news from this wave is that one control worked. StepSecurity found a repository where the attacker's runs stalled because the project required approval before workflows ran. The exfiltration step never ran there.
How to lock it down
GitHub's own security guidance for Actions covers most of what is needed.
Start with review of workflow changes. Add .github/workflows to the CODEOWNERS file and protect the default branch so changes need a pull request and a named reviewer. GitHub's docs recommend this directly. Turn on approval for workflow runs from outside collaborators.
Then shrink the default token. GitHub's guidance is to give the built-in GITHUB_TOKEN "the minimum required permissions." Set it to read-only at the organization level and grant write access per job.
Replace stored cloud keys with OIDC where you can. GitHub Actions can use OpenID Connect to get a short-lived cloud token for each job, with no long-lived secret stored in GitHub. The cloud side should only trust named repositories and branches. AWS, Azure, Google Cloud and HashiCorp Vault are all supported.
Gate release credentials. Put package registry tokens in a protected environment with required reviewers, so a job cannot read them until someone approves. Registries that support trusted publishing, PyPI among them, let you drop the stored token altogether.
Retire classic personal access tokens. Use fine-grained tokens with short expiry, scoped to the repositories that need them, and require phishing-resistant multifactor sign-in for everyone with write access.
Limit runner egress. Allow only the hosts a build needs, and alert on outbound HTTP to bare IP addresses. Keep self-hosted runners away from public repositories, which GitHub says they "should almost never" serve.
Turn on secret scanning with push protection, and handle any alert on an old commit by revoking the key.
For more on pipeline design, see our guides to CI/CD pipelines and securing pipelines for AI and ML.
What IT teams should do
- Search your GitHub organization this week for workflow files named security-audit.yml, github_actions_security.yml or security-check.yml, and for the strings 193.32.204.199, AKIA_CTX_START and c=monami. Check every branch and every fork, not just the default branch.
- If you find one dated August 31 or later, treat it as a breach. Revoke the token or session that made the commit, delete the file from all branches, pause releases and rotate every secret the repository held and every key that ever appeared in its history.
- For any AWS key that may have leaked, check CloudTrail for new IAM users, new access keys and activity in regions you do not use.
- Block 193.32.204.199 on the firewalls in front of self-hosted runners and search past network logs for it.
- Add .github/workflows to CODEOWNERS, require pull requests on default branches and set GITHUB_TOKEN to read-only across the organization.
- Make a 90-day plan to move cloud deploys to OIDC and to retire classic personal access tokens, starting with accounts that have write access to many repositories. Our explainer on identity and access management covers the access review side.
Sources
- StepSecurity: GhostAction returns
- Socket: New GhostAction wave hits hundreds of repos, expanding beyond CI/CD secrets to cloud credentials
- The Hacker News: Credential-stealing GitHub Actions campaign
- Cloud Security Alliance: Research note, GhostAction returns
- GitHub Docs: Secure use reference for GitHub Actions
- GitHub Docs: Configuring OpenID Connect in cloud providers