Blog / Coding tips

GhostAction GitHub Actions Attack: How to Check Your Repos for the Fake "Security Audit" Workflow (October 2026)

Cover image for GhostAction GitHub Actions Attack: How to Check Your Repos for the Fake "Security Audit" Workflow (October 2026)

GhostAction is a credential-theft campaign that uses stolen GitHub accounts to commit a fake workflow, usually .github/workflows/security-audit.yml named "Security Audit", to every repository the account can write to. When it runs, it sends the repository's GitHub Actions secrets, plus any API keys found in the files and the entire git history, to the attacker's server. If that workflow ever ran in your repository, treat every secret it could reach as stolen and rotate it.

The campaign has been active since 2025, but a new wave this month has made it one of the biggest developer security stories of the week. On 8 October 2026, attackers used two compromised maintainer accounts to push the workflow to 345 repositories in minutes, including Uber's athenadriver and the popular pyxel game engine. This guide explains what happened, using reports from StepSecurity, Socket and GitGuardian, and shows how to check your own repositories.

What happened in October 2026?

StepSecurity's analysis describes the 8 October wave:

  • At 13:20 UTC, the account of Takashi Kitao, author of the 18,400-star pyxel engine, pushed the malicious workflow to 27 repositories.
  • Eight hours later, the account of Henry Wu (henrywoo), original author of Uber's athenadriver, pushed it to 318 repositories (39 source repositories and 279 forks) in a 16-minute window, 21:10 to 21:26 UTC.
  • StepSecurity's review of the athenadriver run log shows the exfiltration completed: the attacker's server acknowledged receipt four seconds after the workflow started.

The wider numbers are larger. GitGuardian reported on 7 October that an earlier wave hit 772 public repositories belonging to 373 users and organisations between 31 August and 30 September 2026, targeting 2,577 secrets. Socket added an update on 9 October saying it had identified more than 500 GitHub accounts that had committed the malicious workflow to tens of thousands of repositories since 7 October.

How does the GhostAction attack work?

StepSecurity describes a consistent chain:

  1. Account compromise. The attacker gets a maintainer's GitHub credential, most plausibly a leaked personal access token from infostealer malware logs or credential dumps.
  2. Reconnaissance. It reads the repository's existing workflow files for ${{ secrets.NAME }} references, so it knows the exact secret names to request.
  3. Injection. It commits a workflow that looks like a security improvement directly to the default branch, under the victim's own identity. There's no pull request and no review.
  4. Exfiltration. The workflow runs on the next push, including the injection push itself, and POSTs the secrets over plain HTTP to a hard-coded IP address.

Because the commits come from a real maintainer account, nothing looks unusual in the commit list unless someone reads the workflow file.

What's new in this wave: your git history is exposed

The October variant, "Security Audit" (security-audit.yml), does more than earlier versions. According to StepSecurity and Socket, it:

  • runs on workflow_dispatch and on any push to any branch or tag
  • checks out with fetch-depth: 0, so the runner has every branch and tag
  • sends the repository's named Actions secrets, as before
  • searches the working tree for 13 credential patterns, including AWS keys, Anthropic, OpenAI and OpenRouter keys, GitHub and GitLab tokens, Google/Firebase API keys, Slack tokens and SendGrid keys
  • runs git log -p --all to search the complete history for the same patterns

That last step changes the clean-up. A key committed once in 2019 and deleted the next day is still in the history, so it's harvested too. StepSecurity says that rotating your current Actions secrets "no longer covers the exposure": any secret ever committed to the repository must be treated as compromised.

This is exactly why deleting a file in a new commit isn't enough when it contains a secret. My guide on how to remove a file from a Git repo but keep it locally covers untracking files, but once a key has been pushed, the only real fix is to revoke it.

Indicators to look for

From the StepSecurity and Socket reports:

  • Workflow files: .github/workflows/security-audit.yml, github_actions_security.yml, security-check.yml
  • Workflow names: "Security Audit" (job audit), "Github Actions Security" (job send-secrets), and a step called "Prepare Cache Busting"
  • Commit messages: "Add security audit workflow", "Update security audit workflow", "Add/Update Github Actions Security workflow", "Add security check workflow", "Trigger security scan"
  • Network: connections from runners to 193.32.204.199 (ports 80 and 3000); older waves used 45.139.104.115 and 170.39.218.2
  • Payload markers: AKIA_CTX_START, AKIA_CTX_END, ?c=monami and ?c=new in URLs

StepSecurity's advice is blunt: if a "Security Audit" or "Github Actions Security" workflow appeared in any repository you maintain since 31 August 2026, treat it as a confirmed breach.

How to check your repositories on GitHub

StepSecurity suggests GitHub code searches (logged in, Code tab). Replace your-org with your organisation or username:

org:your-org "AKIA_CTX_START"
org:your-org "c=monami"
org:your-org "193.32.204.199"

For personal accounts, use user:your-username instead of org:. Code search only indexes default branches and excludes forks, so also:

  • open each repository's Actions tab and look for runs named "Security Audit" or "Github Actions Security"
  • check your organisation audit log for direct pushes to default branches that added workflow files, and for workflow_dispatch events on new "audit" workflows
  • check forks you own, since the henrywoo sweep hit 279 forks

How to check a local clone (tested script)

Code search misses non-default branches. This Python script checks every local and remote-tracking branch of a clone for the known file names and indicators, and searches the workflow history for the known commit messages:

"""Check a local git checkout for GhostAction indicators on every branch."""
import subprocess, sys
NAMES = ("security-audit.yml", "github_actions_security.yml", "security-check.yml")
IOCS = ("193.32.204.199", "AKIA_CTX_START", "c=monami", "45.139.104.115", "170.39.218.2")
repo = sys.argv[1] if len(sys.argv) > 1 else "."
git = lambda *a: subprocess.run(["git", "-C", repo, *a], capture_output=True, text=True).stdout
hits = 0
for ref in git("for-each-ref", "--format=%(refname:short)", "refs/heads", "refs/remotes").split():
    for path in git("ls-tree", "-r", "--name-only", ref, "--", ".github/workflows").split():
        body = git("show", f"{ref}:{path}")
        found = [i for i in IOCS if i in body]
        if path.rsplit("/", 1)[-1] in NAMES or found:
            hits += 1; print(f"SUSPICIOUS {ref}:{path} {found}")
log = git("log", "--all", "--format=%h %an %ad %s", "--date=short", "--", ".github/workflows")
for line in log.splitlines():
    low = line.lower()
    if "security audit" in low or "actions security" in low or "trigger security scan" in low:
        hits += 1; print("SUSPICIOUS COMMIT", line)
print("no indicators found" if not hits else f"{hits} indicator(s) found - treat as a breach")

Run git fetch --all first, then python3 gacheck.py path/to/repo. I tested it with Git 2.47 and Python 3.13 on a test repository, first clean, then with a harmless simulated security-audit.yml on a feature branch:

no indicators found
SUSPICIOUS feature:.github/workflows/security-audit.yml ['193.32.204.199']
SUSPICIOUS COMMIT 09ef2cc Dev 2026-10-12 Add security audit workflow
2 indicator(s) found - treat as a breach

A clean result is a good sign, not proof. Always check the Actions run history too, because a workflow can be deleted after it ran.

What to do if you were hit

Based on the researchers' guidance:

  1. Secure the account first. Revoke the compromised user's personal access tokens, SSH keys and OAuth app grants, reset the password and check two-factor authentication. Otherwise the attacker can push again.
  2. Delete the malicious workflow on every branch, not just the default branch.
  3. Rotate every GitHub Actions secret that the repository and its organisation expose to workflows.
  4. Rotate every credential that has ever appeared in the git history, including keys deleted long ago. Search the history yourself with a secret scanner to build the list.
  5. Check your package registries. If tokens for PyPI, npm or crates.io were exposed, check for releases you didn't publish. StepSecurity noted no malicious releases from the compromised pyxel and athenadriver tokens at the time of writing, but warned that this isn't evidence the credentials are safe.
  6. Review cloud provider logs (for example AWS CloudTrail) for activity using exposed keys.

How to protect your repositories

The most striking detail in StepSecurity's report is a repository that wasn't robbed: when the attacker re-triggered the workflow in typecho-fans/plugins, both runs stalled in action_required because the repository requires approval for workflow runs. "A one-setting control broke the kill chain."

Practical defences:

  • Require approval for workflow runs where your setup allows it, especially for outside contributors.
  • Protect .github/workflows/ with branch protection rules or rulesets and a CODEOWNERS entry, so workflow changes need a reviewed pull request.
  • Block direct pushes to default branches, even for maintainers.
  • Turn on secret scanning and push protection, so new keys are blocked before they're committed.
  • Use short-lived credentials, such as OpenID Connect (OIDC) to cloud providers, instead of long-lived keys stored as secrets.
  • Set the default GITHUB_TOKEN permission to read-only. StepSecurity noted the athenadriver run's token was limited to contents: read, so the workflow couldn't push code itself.
  • Use fine-grained personal access tokens with expiry dates, and protect your machine from infostealer malware.
  • Keep secrets out of code in the first place. For front-end projects in particular, see my guide on keeping an AI API key off the browser.

Why this matters for small projects too

It's easy to assume attackers only want big companies. But the October wave hit a long tail of personal projects, because the automation simply pushes to every repository a stolen account can write to. A hobby repository with a cloud key, an AI provider key or a package registry token is just as useful to an attacker. If you maintain anything on GitHub, run the checks above, and make rotating old keys a habit rather than an emergency.

FAQ

What is GhostAction?

A GitHub supply chain campaign, first documented in September 2025, that uses stolen maintainer accounts to commit fake security workflows. When those workflows run, they send repository secrets to an attacker-controlled server.

What is security-audit.yml?

It's the file name of the October 2026 GhostAction workflow, named "Security Audit". It has no security function; it collects Actions secrets and credentials from the files and git history and sends them over HTTP.

How do I know if my GitHub repository was affected?

Search your repositories and Actions run history for "Security Audit" or "Github Actions Security" workflows, the IP address 193.32.204.199 and the marker AKIA_CTX_START, on all branches and forks.

Is deleting the workflow enough?

No. If it ran, the secrets were already sent. Secure the compromised account, delete the workflow everywhere, and rotate every Actions secret and every credential that has ever been in the git history.

Why does git history matter for this attack?

The new variant runs git log -p --all on a full checkout, so it finds credentials in old commits, even ones that were removed from the current code years ago.

How do attackers get into maintainer accounts?

According to StepSecurity, most plausibly through leaked personal access tokens from infostealer malware logs or credential dumps. The commits then appear under the victim's real identity.

How can I stop malicious workflows from running?

Require approval for workflow runs, protect the .github/workflows folder with branch protection and CODEOWNERS, block direct pushes to default branches, and keep the default GITHUB_TOKEN read-only.

Was GitHub itself hacked?

No. Researchers describe abuse of legitimate accounts and repository permissions, not a breach of GitHub's infrastructure.

// note

How to read this note.

This is a learning note from studying the web. It is one small topic, written so I can remember it. It is not a course and not a claim that I have finished the subject.

If a sentence is wrong, say so from the contact page and name this title. Drafts never appear here. Related notes, when they exist, are other published posts, and the same sample rule applies to each of them.