Gheist: stolen GitHub tokens hit 850+ accounts, private repos
Wiz's Gheist report: stolen GitHub tokens planted 13,500+ secret-dumping workflow branches. Private repos weren't held. Hunt ci-sync branches, rotate, expire tokens.
Wiz Research has published Gheist, an automated campaign that uses stolen GitHub tokens to plant secret-dumping workflows in every repository a token can reach. Wiz counts more than 13,500 planted branches across more than 850 compromised accounts. GitHub's newer workflow-hold control stopped the payload in public repos. It does not cover private repos or GitHub Enterprise Server, and there Wiz saw the attack succeed. If your business code lives in a private GitHub repo with deploy secrets attached, this one is about you.
What actually happened
Per the Wiz Research write-up, published October 25:
- Tracked since September 15, 2026. Named after the
gheistuser agent in its API calls. - Token source: Wiz says the tokens it could trace fit infostealer logs and tokens exposed in earlier supply-chain compromises.
- The play: create a
ci-sync-branch with six random characters, commit.github/workflows/sync-check.yml, and have the workflow print thesecretscontext base32-encoded. GitHub masks secrets only when they appear verbatim, so the encoded copy goes straight into the log. The tool pulls the log through GitHub's API and deletes the run seconds later. No attacker domain to block. - Later versions used an environment matrix to print environment-scoped secrets, often production credentials, and added a job that searches self-hosted runners for credentials.
- Impact: in enterprise orgs, Wiz saw the tool clone private repos and, hours later, use stolen cloud credentials to enumerate AWS Secrets Manager.
Wiz says GitHub has held potentially malicious workflow runs in public repos until a collaborator approves them since July 28, and every public Gheist run it checked was held. Private repos and GHES had no such hold.
Why stolen GitHub tokens matter for your business
A long-lived personal access token on a developer's laptop is a key to every repo that person can push to, and every secret those repos' workflows can read. One infostealer infection turns that into your AWS account.
What we would do today:
- Hunt. Search for branches matching
^ci-sync-[0-9a-z]{6}$with the commit messageci: sync config. Check audit logs for workflow runs deleted right after they finished. - Rotate, don't clean up. Deleting the branch does not un-leak the secret. Rotate everything those repos could reach.
- Gate production. Require reviewers on environments that hold production secrets, and scope OIDC trust to protected branches.
- Expire your tokens. GitHub CLI 2.103.0 added
gh auth login --expiring. GitHub says a leaked access token becomes unusable within hours. Make it the default withgh config set expiring_credentials enabled.
Key takeaways
- Gheist used stolen GitHub tokens to plant 13,500+ secret-dumping branches across 850+ accounts
- Secrets leave base32-encoded through GitHub's own logs, so masking and domain blocks miss it
- GitHub's workflow hold protected public repos; private repos and GHES were not covered
- Hunt for ci-sync branches, rotate exposed secrets, gate production environments, and switch gh to expiring tokens
Your CI pipeline holds the keys to production. We set up GitHub repos and deploy pipelines with short-lived credentials, gated environments and secrets scoped to the job. See how we build, or ask us to audit your GitHub setup.
Sources: Wiz Research: Gheist, GitHub Changelog: expiring gh OAuth tokens.
- #github
- #github-actions
- #stolen-tokens
- #supply-chain
- #secrets
Tommy Rush — Founder, Rush Commerce
Operator turned builder. 15+ years running operations — now shipping the systems businesses run on. More
Get The Rush Report weekly — one email, zero fluff.
Keep reading
OVHcloud CLI backdoored: turn on GitHub release immutability
A hijacked account swapped OVHcloud CLI GitHub releases 0.11.0–0.15.0 for secret-stealing builds. Release immutability was off. Here's the fix.
Read itGemini API now stores prompts by default on new paid projects
Since October 26, new paid Gemini API projects log generateContent requests by default for 55 days. How to set store=false and keep customer data out.
Read it