cd /news/ai-safety/gheist-13500-secret-dumping-workflow… · home › topics › ai-safety › article
[ARTICLE · art-157746] src=dev.to ↗ pub= topic=ai-safety verified=true sentiment=↓ negative

Gheist: 13,500 secret-dumping workflows planted with stolen GitHub tokens — audit yours in 5 minutes

A five-week campaign dubbed Gheist used stolen GitHub tokens to plant secret-dumping workflows in 13,500 branches across more than 850 compromised accounts, including private enterprise repositories, according to an autopsy published by Wiz. The workflows dumped environment variables and secrets — including Anthropic, Hugging Face, Groq and NVIDIA API keys — to logs that were then fetched and deleted via the GitHub API, and Wiz confirmed follow-on AWS role assumption from stolen cloud credentials via CloudTrail. Public repositories were largely spared by GitHub's approval hold on first-time contributor workflow runs, a guardrail that does not apply to private repos or GitHub Enterprise Server.

by read4 min views3 publishedOct 26, 2026

While everyone watched LiteLLM, a quieter campaign spent five weeks doing something worse: taking stolen GitHub tokens and committing a secret-dumping workflow into every repository they could reach — 13,500 planted branches across 850+ compromised accounts, personal projects and private enterprise repos included. Wiz published the full autopsy yesterday. The campaign is called Gheist, it dumps your org secrets, your cloud credentials, and — the line that made me write this — it specifically hunts AI provider keys: Anthropic, Hugging Face, Groq, NVIDIA. Your agents' keys, straight out of your CI.

This post is the mechanics and the audit. The whole check runs in five minutes with gh, tonight, on your own account and orgs.

Gheist's tooling takes a stolen token (sourced from infostealer logs and prior supply-chain incidents — the same family that hit Trivy in March), enumerates every repo it can touch, and plants a branch ci-sync-XXXXXX containing one workflow, committed as ci: sync config, unsigned. The workflow is two dumb lines: dump env and toJSON(secrets), base32-encoded, print to the workflow log. Then the tool fetches the log through GitHub's API and deletes the run.

Four details make it clever, and all four are worth internalizing:

$SECRET prints safely to the attacker.permissions: {} protects nothing here.secrets context. Half the hardening advice on the internet answers a different attack. On self-hosted runners the payload went further — searching for 31 token formats (private keys, .env files, Terraform state, /proc/*/environ, Docker sockets, Kubernetes tokens) and AI provider keys specifically. Wiz notes that variant is buggy — wrong runner paths, broken regex, no GCP/Azure collection — which is somehow worse: the campaign is a product under active iteration, shipping features.

The single most interesting fact in the autopsy: public repos were largely saved by one quiet GitHub guardrail. Since July 28, workflow runs from first-time contributors in public repos sit in action_required pending collaborator approval — and every public Gheist run Wiz checked sat there, payload never executed.

That hold doesn't apply to private repos or GitHub Enterprise Server. There, the workflows ran, secrets were dumped, and Wiz proved follow-on AWS role assumption from the stolen cloud credentials via CloudTrail. The guardrail you never configured protected your open source; nothing protected the private stuff, which is where the secrets actually live.

Two more findings worth the price of admission: permissions: {} on the malicious workflow was used by the attacker — cosmetically, since secrets don't care — and about two-thirds of the implicated accounts have since vanished from GitHub, suggesting response is underway while the campaign kept evolving through October 24.

The radar: the commit message is searchable in public history, and it's noisy (legit sync config commits everywhere), so treat it as a lead generator, not a verdict:

gh api 'search/commits?q="ci: sync config"' --jq '.total_count'

The actual self-audit — planted branches on your account (loop your repos, grep the branch pattern):

gh repo list --limit 200 --json nameWithOwner --jq '.[].nameWithOwner' | while read r; do
  gh api "repos/$r/branches" --paginate --jq '.[].name' 2>/dev/null | grep -E '^ci-sync-[0-9a-z]{6}$' && echo "  ↑ HIT in $r"
done

For organizations (org owners only — the audit-log API isn't available on personal accounts; the web UI's security log is the personal fallback):

gh api 'orgs/YOURORG/audit-log?include=all&phrase=workflow_run' \
  --jq '.[] | select(.action=="workflow_run.deleted")'
gh api 'orgs/YOURORG/audit-log?include=all' --jq '.[] | select(.user_agent=="gheist")'

And the cloud-side hunt that works even without GitHub logs — Wiz's best trick: OIDC role assumptions whose session/subject contains ci-sync- (GitHub's OIDC subject includes the ref, so the planted branch name travels into your CloudTrail):

aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity \
  --start-time 2026-09-15 --max-results 20 | grep -i 'ci-sync'

If anything hits: rotate every secret that repo could see — deleting runs doesn't un-dump them — revoke the pushing tokens, and check the token owners' machines for infostealers, because that's where the tokens came from.

From Wiz's list, ranked by how little they cost: require reviewers on environment-scoped secrets (kills the environment matrix); scope OIDC trust policies to protected branches only (kills ci-sync-* role assumption); prefer GitHub Apps or fine-grained, short-lived tokens over classic PATs (shrinks what one stolen token reaches); run self-hosted runners ephemerally, no Docker socket, no unrestricted metadata (kills the host pivot). And never approve a held sync-check run sitting in action_required — that's the trap's front door.

Gheist = stolen tokens + one two-line workflow + base32 + GitHub-as-C2, at a scale of 13,500 branches. Public repos got lucky via the first-contribution hold; private repos paid. The audit is five minutes of gh and one CloudTrail query — and if you run AI agents in CI, the campaign's shopping list literally names your provider. Check tonight.

Sources: Wiz — Gheist: attempted scaled abuse of stolen GitHub tokens · CISA KEV / alerts hub · commit-search audit via gh api (commands above, verified live)

── more in #ai-safety 4 stories · sorted by recency
── more on @gheist 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/gheist-13500-secret-…] indexed:0 read:4min 2026-10-26 · —