GhostAction: A Fake "Security Audit" Workflow Reached 30,000 Repositories

Attackers did not exploit anything. They logged in with credentials somebody else had already stolen, then added a file called security-audit.yml to every repository they could write to. The irony is the point: the workflow that drains your secrets is named after the thing that should protect them.

Security News 8 min read

GhostAction: A Fake "Security Audit" Workflow Reached 30,000 Repositories

Between 8 and 12 October 2026, with a sharp spike on 8 and 9 October, a credential-theft campaign known as GhostAction escalated to target more than 30,000 repositories across 3,000 users and organisations on GitHub, using approximately 1,900 compromised accounts. The campaign attempted to extract 3,174 secrets from public repositories' CI/CD workflows.

The method is simple to the point of being unremarkable. Attackers obtain write access using stolen Personal Access Tokens or credentials harvested by infostealers, then push a workflow file with a reassuring name, most often security-audit.yml or github_actions_security.yml, into the default branch of every repository that account can modify.

The workflow collects the Actions secrets referenced by the project's existing workflows and sends them to an attacker-controlled endpoint.

GhostAction is not new. GitGuardian researchers Gaetan Ferry and Guillaume Valadon, who have tracked it since first disclosing it in September 2025, summarised its return plainly: "The campaign we revealed back in September 2025 is back."

One important qualification on scale. GitHub began preventing the malicious workflow from running on 9 October, which means the two waves that followed could not extract any secrets. The 30,000 figure describes repositories targeted, not repositories successfully drained. The risk that remains is concentrated in earlier victims whose secrets were never rotated.


What happened

The campaign across three waves

Period

Scope

Outcome

September 2025 (original disclosure)

817 public repositories, 327 GitHub users

At least 3,325 secrets exfiltrated

31 August to 30 September 2026

772 public repositories, 373 users and organisations

2,577 secrets targeted, with confirmed exfiltration

8 to 12 October 2026

30,000+ repositories, 3,000 users and organisations, ~1,900 accounts

3,174 secrets attempted, blocked from 9 October

The October surge is what drew attention, but the September wave is where the confirmed losses sit.

How it works, step by step

1. Credentials arrive pre-stolen. Attackers do not break into GitHub. They use Personal Access Tokens or account credentials already harvested by infostealer malware running on developers' machines. No GitHub vulnerability is involved at any stage.

2. A workflow is pushed to every writable repository. Using a hijacked maintainer account, the attacker commits a file to .github/workflows/. The commit messages observed are deliberately boring: "Add security audit workflow", "Update security audit workflow" and "Add Github Actions Security workflow".

3. Reconnaissance identifies which secrets exist. The workflow does not guess. It reads the repository's existing workflows to find which named Actions secrets the project actually uses, then references those specific names.

4. Secrets are concatenated and exfiltrated. The workflow builds a string of secret names and values and sends it to an external endpoint. Researchers documented the exfiltration address 193.32.204.199.

What they were after

The target list reflects what modern CI/CD pipelines actually hold:

  • Package registry tokens: PyPI passwords, crates.io tokens, npm and other publishing credentials

  • GitHub Personal Access Tokens

  • Cloud credentials, with payloads evolving to scan specifically for AWS keys

  • GitLab tokens

  • AI provider API keys, a newer category and a direct route to billable compute

The inclusion of package publishing credentials is the part with the longest tail. A stolen PyPI or crates.io token is not just a loss for the maintainer. It is the ability to publish a malicious version of a package that other people depend on.

Notable victims

Two compromised maintainer accounts, kitao and henrywoo, pushed the workflow into every repository they could write to. Affected projects included kitao/pyxel, which has over 18,000 stars, and uber/athenadriver. Socket reported that the 8 October activity affected 346 repositories connected to those two accounts.

What limited the damage

Two things, and both are worth noting because they explain why 30,000 repositories did not become 30,000 breaches.

GitHub held most workflow runs for approval. Of 3,669 runs GitGuardian collected, most were held rather than executed. GitHub's default behaviour of requiring approval for workflow runs from first-time or outside contributors did real work here.

GitHub blocked the malicious workflow from 9 October. The waves that followed were ineffective.

Neither of these helps anyone compromised during the September wave, when exfiltration was confirmed.


Why it matters

There is nothing to patch. No software flaw is involved. The attack is entirely a consequence of valid credentials plus write access plus a CI/CD system that is designed to run whatever code sits in the repository. Vulnerability management does not address this.

The naming is the social engineering. A file called security-audit.yml in a project's workflows directory looks like diligence. A maintainer glancing at a commit list sees "Add security audit workflow" and reads it as somebody being helpful. The deception is aimed at the human review step, not at any technical control.

Infostealers are the supply line. The credentials that enabled this were stolen from developer machines by commodity malware, often long before the campaign used them. Every developer endpoint is an access path into every repository that developer can write to.

CI/CD secrets are the crown jewels now. A single compromised pipeline yields cloud credentials, publishing tokens and AI API keys. That is production infrastructure, software distribution and a billing account in one place.

Unrotated secrets are the real exposure. Researchers note that the campaign's continued activity suggests reliance on secrets that were never rotated after earlier compromises. The 2025 wave exfiltrated at least 3,325 secrets. Any of those still valid today remains usable.


Who is affected

  • Maintainers of any repository that received the malicious workflow since 31 August 2026.

  • Anyone compromised in the September 2025 or September 2026 waves, where exfiltration was confirmed and secrets may still be live.

  • Forks of infected repositories, which can carry the workflow file onward.

  • Downstream consumers of affected packages, if publishing credentials were taken and used.

  • Organisations whose developers have been hit by infostealer malware, which is the upstream condition for the whole campaign.

  • Teams storing cloud or AI provider keys as Actions secrets, which is standard practice and therefore a very large group.


What organisations should do

Check for the workflow

  1. Search every repository for .github/workflows/security-audit.yml and .github/workflows/github_actions_security.yml, added on or after 31 August 2026.

  2. Check commit history for the messages "Add security audit workflow", "Update security audit workflow" and "Add Github Actions Security workflow".

  3. Search across all branches, not just the default branch, and check forks of any affected repository.

  4. Review workflow run history for executions of those files, and check whether runs were held for approval or actually executed. The difference determines whether secrets left the building.

If you find it, treat the repository as compromised

StepSecurity, Socket and GitGuardian all give the same advice, and the order matters:

  1. Revoke the compromised GitHub credential, including the Personal Access Token used to push the workflow.

  2. Rotate every secret the repository's workflows reference. Not just the ones you think were read. The workflow enumerated them from your existing configuration.

  3. Delete the malicious workflow from all branches, and from forks where you have control.

  4. Audit what those credentials could reach, particularly cloud accounts, package registries and AI provider billing.

  5. Check package registries for unexpected releases published with stolen tokens.

Reduce the standing exposure

  1. Treat Personal Access Tokens as short-lived. Set expiry dates, scope them narrowly, and prefer fine-grained tokens over classic ones.

  2. Require approval for workflow runs from outside and first-time contributors. GitHub's defaults blunted this campaign and are worth verifying rather than assuming.

  3. Protect the default branch so that workflow files cannot be added without review. A branch protection rule requiring review on .github/workflows/ would have stopped the push entirely.

  4. Use OIDC federation instead of long-lived cloud credentials where your provider supports it, so there is no static secret to steal.

  5. Rotate CI/CD secrets on a schedule, not only after an incident. The campaign's persistence depends on secrets that nobody ever changed.

  6. Monitor developer endpoints for infostealer infections, and treat any such infection as an identity incident: assume every token on that machine is compromised and revoke accordingly.


Final thoughts

The attackers wrote no exploit and found no bug. They used passwords somebody else had already stolen, added a file with a trustworthy name, and let GitHub's own automation do the work. The entire campaign is a demonstration that a CI/CD pipeline is a remote code execution service that you have deliberately pointed at your own secrets.

The lesson: in CI/CD, write access to a repository is equivalent to read access to every secret that repository uses. Most teams do not think of it that way. They think of repository permissions as controlling code and of secrets as being protected separately. The workflow file collapses that distinction, because anyone who can add a workflow can ask for the secrets by name.

The second lesson concerns rotation. GitHub blocked the October waves, and most runs were held for approval, so the headline figure of 30,000 repositories overstates actual losses considerably. But the September 2025 wave exfiltrated at least 3,325 secrets, and the campaign's continued viability suggests many of those were never changed. A stolen credential that nobody rotates does not expire. It just waits.

Two things worth doing today: search your organisation for those two filenames across all branches, and pick one CI/CD secret at random and find out when it was last rotated.

Blog

Security 10 min read

Every Account, No Exceptions: What the Fakturownia Breach Means for the Businesses That Used It

An intruder spent roughly 38 hours inside Poland's largest invoicing platform and copied a large part of the database. The company's own statement says the incident concerns every account. For the businesses affected, the hardest part is not the password reset. It is that each of them is now a data controller with its own legal obligations.