TECHDEV · Flagship · Open-source tool
gheist-guard
A local, deterministic, read-only behavioral detector for the Gheist planted-workflow attack shape: one command, one verdict per repository, one rotate checklist.
TypeScript · Zero runtime dependencies · MIT · Node 20+ · Read-only by default · No model, no account, no secret values ever printed.
Not the Pokémon move or the Elder Scrolls spell: this gheist-guard is a local CLI detector for the Gheist planted-workflow campaign Wiz reported (~2026-10-26).
The attack it watches for
A token stolen from one developer machine becomes an organization-wide secret dump with no strange domain and no outbound connection for a firewall to catch. The attacker pushes a branch named ci-sync- plus six characters, commits a workflow that prints repository secrets base32-encoded into the run log (GitHub masks secret values only when they appear verbatim), then downloads the log through the GitHub API and deletes the run within seconds. Wiz Research recovered more than 13,500 planted branches from more than 850 compromised accounts in its October 2026 reporting. GitHub's July 28, 2026 control holds suspicious runs in public repositories for collaborator approval, but it does not cover private repositories or GitHub Enterprise Server — exactly where this attack succeeds. Deleting the branch or the run does not undo the exposure: every secret the run could read must be rotated.
“Gheist” is the name Wiz Research gave to the campaign it reported in October 2026. This tool is not affiliated with, endorsed by, or connected to Wiz, and it does not claim to be the first to detect any campaign. A dump workflow contains no secret text, so no content scanner flags it — gheist-guard watches the act, from the evidence that survives it.
What it checks
| Rule | Evidence |
|---|---|
| R1 — Branch pattern | Branch matches ^ci-sync-[0-9a-z]{6}$ |
| R2 — Workflow identity | .github/workflows/sync-check.yml with commit “ci: sync config” |
| R3 — Dump content | Base32/base64 secret-dumping content in the workflow |
| R4 — Run lifecycle | Run completed, then deleted within 60 seconds |
| R5 — Tool fingerprint | GitHub API user agent “gheist” |
| R7 — Self-hosted variant | Job named sync-host hunting credentials on the runner |
Full rule reference: docs/RULES.md in the repository.
Verdicts
| Verdict | Meaning | Exit code |
|---|---|---|
| CLEAR | No rule fires. | 0 |
| SUSPECT | A rule fires, but the full documented combination is not present. Carries the exact next check to run — never a rotation demand, never silently CLEAR. | 1 |
| CONFIRMED | Branch pattern (R1) plus any of workflow identity (R2), dump content (R3), run lifecycle (R4), tool fingerprint (R5), or the self-hosted variant (R7). Always carries the ordered rotate checklist. | 1 |
Exit code 2 means a usage or API error. One stderr summary line is always printed. The name “Gheist” appears in a verdict only when the full documented pattern matches.
Install from source
git clone https://github.com/techdevfun/gheist-guard.git
cd gheist-guard
npm ci
npm run build
node dist/cli.js scan <owner/repo>Commands copied exactly from the gheist-guard README (v0.1.1). Do not use npm install -g gheist-guard yet — the README lists it as “once published to npm”. Requires Node 20 or later. A fine-grained token with repository read scope is enough for the REST path; it may come from --token or GITHUB_TOKEN.
Examples
# Scan one repository (REST path, read-only)
node dist/cli.js scan <owner/repo>
# Scan every repository in an organization (REST path)
node dist/cli.js scan --org <org>
# Audit-log path (organization-owner token required for live use;
# --events runs it against recorded audit-log payloads)
node dist/cli.js audit --org <org> --events audit-events.json
# Re-print the rotate checklist from a saved report, without re-scanning
node dist/cli.js scan <owner/repo> > report.json
node dist/cli.js checklist <owner/repo> --report report.jsonLegitimate automation can be allowlisted and is reported as SKIPPED with a reason, never silently dropped (see the README for --allow-branch-pattern and --allow-workflow).
The rotate checklist (CONFIRMED only, in order)
- Revoke the pushing token.
- Rotate every secret name the run could read.
- Check OIDC roles assumable from the matched ref.
- Check the pushing machine for infostealer compromise.
The checklist lists secret names only. The tool never prints, stores, or transmits a secret value, and v1 never deletes, rotates, or revokes anything — the operator does it.
Measured numbers (README, build 2026-10-27)
- Test suite: 52/52 green (TypeScript strict, clean).
- Fixture verdicts: CONFIRMED on every planted fixture; CLEAR on every legitimate fixture; SUSPECT (never CONFIRMED, never silent CLEAR) on every partial-signal fixture.
- False-positive probe: 24 legitimate branch names + 5 legitimate workflows → 0 CONFIRMED, 1 SUSPECT (
ci-sync-configmatches the six-character pattern by design; documented boundary). - Live REST end-to-end (real GitHub API, read-only, 2026-10-27): 3 real repositories scanned, all CLEAR, exit 0; plus a private scratch repository with a branch-only plant: SUSPECT pre-fix (R1 only) and CONFIRMED post-fix (R1+R2+R3) on verbatim live state.
What this is NOT — and its limits
- Not a static secret scanner (that is Gitleaks/TruffleHog's job, explicitly out of scope). Not a SIEM, monitoring service, malware database, or auto-remediation tool.
- Not a prevention control for public repositories: GitHub's approval hold already does that job, and this tool never approves held runs.
- Audit-log path is fixture-tested only, end to end: no organization-owner account was available for a live audit-log test. The report always states which path ran; the REST path is the live-measured path.
- GitHub Enterprise Server site-admin logs are documented but untested (no instance available). Pull-request association is an approximation: a workflow commit with an associated pull request is treated as reviewed.
- Where rivals beat us (from the README, honestly): GitHub's native controls beat us on authority and position; Socket, StepSecurity and GitGuardian beat us on threat-intelligence scale; Gitleaks and TruffleHog beat us on secret-pattern breadth; SIEM tooling beats us on central correlation; manual runbooks beat us on zero-install immediacy.
Source + README on GitHub → · Report an issue → · ask@techdev.fun
Related tools
More open-source tools from TECHDEV: sessguard, runverdict, vetgate, context-diet, ci-failure-detective, agent-seatbelt, devsecops-os, env-doctor, skill-audit, logtrim, testguard, breakcheck, keymap, memgraph, ggufit, leaseguard, factfence, jsonfold
Have a say
Vote for this tool, suggest a feature, or discuss it with other operators on the community board.