Daily Top · Supply chain / CI/CD / Identity

GitHub held Gheist on public repos. The private run already printed the secrets.

Wiz 25 October. Stolen GitHub tokens plant sync-check.yml on every reachable repo. Secrets leave as base32 in Actions logs through GitHub's own API. The July hold does not cover private repositories or GitHub Enterprise Server. Deleting the branch is not the rotation.

RWP Ventures · 2026-10-26 · event 2026-09-15 · 12 min read · priority 8.9

Bottom line up front

CONFIRMED On 25 October 2026 Wiz Research published Gheist, a campaign it has tracked since 15 September. Stolen GitHub tokens plant a workflow named sync-check on every repository the token can write. The job prints the runner environment and the GitHub secrets context as base32, so GitHub's log mask does not match. The tool then downloads the log through the GitHub API and deletes the run seconds later. API requests carry the user agent gheist. Wiz recovered more than 13,500 planted branches from more than 850 compromised accounts, including enterprise private repositories.

Do not collapse five facts.

  1. The July hold is public-only. Since 28 July 2026, GitHub Actions holds some workflow runs in public repositories on github.com until a write collaborator approves them from an authenticated web session. Wiz: every public Gheist run it checked, including the later self-hosted job, sat at action_required. The payload did not run. GitHub's own changelog: the hold does not apply to private repositories, and GitHub Enterprise Server does not have it.
  2. Private and GHES already executed. Audit logs show ci-sync-* runs completing, then being deleted by the gheist user agent. CloudTrail showed the organization's own workflows running on those branches and assuming AWS roles. That is Actions without the hold, not a scan.
  3. Deleting the branch is not the close. The secrets left in the log before the run was deleted. Rotate every repository, organization, and environment secret the repository could read. Revoke the token that pushed. A clean git history is a hygiene step, not a rotation.
  4. This is not a CVE and not yesterday's LiteLLM wheels. Gheist is stolen-token abuse. Anyone with write access can read the secrets the workflow can see; GitHub documents that. It is distinct from GhostAction (different workflow files; GhostAction exfil to 193.32.204.199). It is distinct from [LiteLLM 1.107.0](/posts/2026-10-25-litellm-11070-cook-pth/). Same class of GitHub workflow theft, different operator, different payload, different blast radius.
  5. This is not Collabora, not Arista, and not a PLC. CISA KEV is still catalog 2026.10.23 / 1756. [CVE-2026-110447](/posts/2026-10-24-collabora-code-cve-2026-110447-kev/) and [CVE-2026-114625](/posts/2026-10-23-arista-velocloud-cve-2026-114625/) are due today, 26 October. No Gheist CVE is on that list.

The operator sentence: if any private repo or GHES instance has a ci-sync- branch whose only commit is .github/workflows/sync-check.yml with message ci: sync config, assume the secrets printed, rotate them from a clean identity, revoke the pushing token, and do not approve a held sync-check run.

What happened

Gheist is not a GitHub product bug. It is an automated harvester sitting on tokens that already had write access.

For each reachable repository the tool creates a branch named ci-sync- plus six random characters, then commits .github/workflows/sync-check.yml with message ci: sync config. The commit is unsigned and authored as the token owner. The push starts the workflow.

High-level, from Wiz. This is not a how-to.

Two tools ran in parallel.

VariantDistinguisherNotes
Tool AHexadecimal branch suffixPlain payload
Tool BBase36 suffixFrom 28 September: timeout-minutes: 6 and the environment matrix, payload varied per repository

On 19 October, Tool B inserted echo X | base32 -w 120 between dumps, which prints LAFA====, assessed as a parser separator. Hours later it pushed a second job, sync-host, runs-on: self-hosted, apparently only to repositories with a registered self-hosted runner. That job writes .gdmp_pat, .gdmp_patg, .gdmp_sweep and logs stages under ===== gdmp-pivot:. Wiz describes it as buggy (wrong runner key file, broken URL-credential regex, does not collect GCP or Azure tokens) and reports no successful run.

In enterprise organizations Wiz saw the tool cycle through tokens of several users and automation accounts within minutes, clone private repositories before planting the workflow, and hours later use cloud credentials from the same organization to enumerate AWS Secrets Manager.

As of 24 October: the campaign was ongoing and evolving. Roughly two-thirds of implicated accounts were no longer on GitHub. Wiz reported the activity to GitHub and assesses the disappearances as response, not as the operator going quiet.

Why it matters

Three operational reasons this is the daily.

First, the control you already have does not cover the repos that hold production secrets. The July hold worked on public github.com. Private repositories and GHES — the places with environment secrets, OIDC cloud roles, and self-hosted runners — executed. A dashboard that only shows held public runs is a false green.

Second, exfil rides a channel defenders allow. There is no webhook.site, no pastebin, no odd ASN on the workflow's egress. The job talks to GitHub. Network allow-lists that "only GitHub" do not catch it. Detection is audit-log and CloudTrail, or the branch itself.

Third, the account is already in a shared credential pool. Wiz traces some tokens to infostealer logs and to tokens exposed in earlier supply-chain events, including the March Trivy compromise. The same accounts show other operators: 6 October lure-repo renames (391 accounts, ~1,461 repos, wiping 610 ci-sync branches as a side effect); 18 October "Windows RDP Runner" free-compute attempts on 25 Gheist accounts; PolinRider loaders re-pushed onto three Gheist commits on 19–20 October; 57 first-phase accounts were also Megalodon victims in May. That is overlap on compromised identities, not attribution of Gheist to those campaigns.

Who / what is affected

Technical context

Defensive mapping, not an exploit recipe. Wiz already printed the public workflow. RWP is not publishing the self-hosted job body.

ATT&CK (defensive, not attribution): T1078 valid accounts (stolen GitHub tokens); T1552.001 credentials in files / CI secrets; T1195 supply-chain adjacent (workflow as the collection step, not a poisoned package); T1562 impair defenses (delete the run); T1098 account manipulation only where other operators later rewrite the same repos. Actor identity: UNKNOWN. Nation-state for Gheist itself: UNKNOWN. Wiz did not attribute Gheist to a DPRK actor. PolinRider on three overlapping victim repos is a separate infection on already-stolen accounts.

Published indicators (Wiz / THN):

IndicatorValue
User agentgheist
Branch^ci-sync-[0-9a-z]{6}$
Commit messageci: sync config, adding only .github/workflows/sync-check.yml
Workflow strings`toJSON(secrets) }}' \base32 -w 120; ===== gdmp-pivot:`
Host files.gdmp_pat, .gdmp_patg, .gdmp_sweep
Git blob SHA (plain)f3da2b8b357dcda02fd455d314be2a95007516a6
Git blob SHA (timeout)d09535857a741bbb976bdc084a9a021713133291
Git blob SHA (separator)1dc5af9cce950aad1eb1546ecce8565b117540c4
Git blob SHA (self-hosted job)c665b778b2d822453293003e7ca0bbb2cb08e39d

Environment-matrix variants differ per repository and have no single hash.

OIDC detection that does not need GitHub logs: if workflows federate to a cloud provider, look for role assumptions or token exchanges whose subject includes a ci-sync- branch. GitHub's OIDC subject includes the branch name when the job is not bound to a deployment environment. Wiz used that to prove Actions ran.

Threat / exploitation status

ClaimStatusEvidence
Stolen GitHub tokens plant sync-check.yml on ci-sync-* branchesCONFIRMEDWiz 25 Oct
>13,500 branches, >850 accounts, including enterprise private reposCONFIRMEDWiz
Secrets printed as base32 in Actions logs, log pulled via GitHub API, run deletedCONFIRMEDWiz; THN 26 Oct
Public github.com runs held at action_required; payload did not run in those checksCONFIRMEDWiz; GitHub changelog 28 Jul 2026
Hold does not cover private repos or GHESCONFIRMEDGitHub changelog; Wiz audit-log and CloudTrail
Private / GHES runs completed and were deleted by user agent gheistCONFIRMEDWiz
Cloud credentials from the same orgs used to enumerate AWS Secrets ManagerCONFIRMED (follow-on)Wiz; origin of those cloud creds not fully named
Campaign ongoing and evolving as of 24 OctCONFIRMEDWiz
Distinct from GhostActionCONFIRMEDWiz; GitGuardian GhostAction uses different workflows and 193.32.204.199
Distinct from LiteLLM 1.107.0 cook.pthCONFIRMEDdifferent artifact, different vendor, different dates
sync-host self-hosted job successful in the wildNOT shownWiz: buggy; no successful run reported
Gheist attributed to DPRK / PolinRider operatorNOT shownthree overlapping victim repos; Wiz does not attribute Gheist
Victim-org census, ransomware useUNKNOWNnot in this retrieval
Gheist CVE on CISA KEV catalog 2026.10.23 / 1756CONFIRMED absentKEV JSON this run

What defenders should do

  1. Hunt the branch, not the hash. List branches matching ^ci-sync-[0-9a-z]{6}$ whose only change is .github/workflows/sync-check.yml with commit ci: sync config. Environment-matrix copies will not match the four blob SHAs. Unsigned commit, authored as a real org member, is expected — that is the stolen token.
  2. Audit log. Workflow runs on ci-sync-* deleted within a minute of completion. Any API activity with user agent gheist. Do not treat a missing run as a miss; deletion is the design.
  3. CloudTrail / equivalent without GitHub logs. OIDC role assumption or token exchange whose subject contains ci-sync-. That is the private-repo proof Wiz used.
  4. Self-hosted runners. Files .gdmp_pat, .gdmp_patg, .gdmp_sweep. String gdmp-pivot in job logs. If present, isolate the runner, rotate its instance role, and treat Docker socket / host filesystem as in-scope even though Wiz has not confirmed a successful sync-host run.
  5. If you find a hit: rotate first. Every repository, organization, and environment secret that repo could read — including production environment secrets and cloud keys the workflows federate. Revoke the pushing credential. Check that identity's laptop for infostealers. Rotate downstream (PyPI, npm, cloud, AI provider keys) that the dumped secrets could mint. Deleting the branch is last.
  6. Do not approve held sync-check runs. Do not check out or run code from ci-sync branches.
  7. Harden so the next stolen token prints less. Required reviewers on environments that hold production secrets (a job cannot read those secrets until a reviewer approves). Scope OIDC trust policies to protected branches or named environments, not *. Prefer GitHub Apps or short-lived fine-grained tokens over classic PATs. Run self-hosted runners as ephemeral VMs without Docker socket or open cloud metadata.
  8. Do not close adjacent tickets on this row. [Collabora 110447](/posts/2026-10-24-collabora-code-cve-2026-110447-kev/) and [Arista VCO 114625](/posts/2026-10-23-arista-velocloud-cve-2026-114625/) are due today. [LiteLLM 1.107.0](/posts/2026-10-25-litellm-11070-cook-pth/) is still cook.pth on a dirty interpreter. GhostAction is a different workflow. Huntress's Microsoft 365 token-spray (79 orgs, 14 July–22 September, published 22 October) is a different identity plane.

RWP assessment

High confidence that Gheist is a real, ongoing stolen-token campaign that plants sync-check.yml on ci-sync-* branches, that public github.com runs Wiz checked were held, and that private repositories and GitHub Enterprise Server executed the payload and deleted the runs.

High confidence that encoded toJSON(secrets) defeats verbatim log masking, that an empty permissions block is not a secrets control, and that deleting the run or branch does not retract secrets that already printed.

High confidence that this is not GhostAction, not LiteLLM 1.107.0, not a GitHub zero-day CVE, and not on KEV catalog 2026.10.23 / 1756.

Moderate confidence in the AWS Secrets Manager follow-on as Gheist-derived rather than a second operator on the same stolen cloud keys. Wiz observed it in the same organizations, hours later. Origin of those cloud credentials is not fully named.

Low confidence in actor identity, in how many of the 13,500 branches produced a usable secret dump, and in whether the 19 October self-hosted job ever ran cleanly after the public write-up.

Confidence that this is not OT process impact: high. No evidence in this retrieval that a controller, safety system, or physical process was affected.

This outranked the rest of the window because it is a new campaign, never a Daily Top, with a primary technical report in the last 24 hours, confirmed execution in private/GHES, a built-in false green (the public hold), and a built-in false close (delete the branch). Collabora and Arista are Friday's KEV rows; their federal clock runs out today. Huntress's M365 token-spray is real BEC tradecraft, but the campaign window ended 22 September and the Huntress post is 22 October — secondary THN pickup today is not a material increment. BlackX is a 2022 Baton Drop bootkit on diplomatic endpoints from early 2026, disclosed 22 October; the interesting control lesson (manual Secure Boot revocation) is not today's CI incident. PHP2Shell remains off KEV.

What we are watching

Sources

Primary: Wiz Research, 25 October 2026 (campaign mechanics, variants, hold vs private/GHES, IOCs, AWS follow-on). Independent secondary: The Hacker News, 26 October. Control documentation: GitHub changelog 28 July 2026 (hold scope); GitHub Actions security and OIDC docs. Catalog check this run: CISA KEV JSON 2026.10.23 / 1756. Adjacent, not this story: GitGuardian GhostAction (distinct); Huntress M365 token-spray 22 October; LiteLLM Daily Top 25 October; Collabora Daily Top 24 October; Arista Daily Top 23 October.

Sources

  1. Wiz Research — Gheist: Attempted Scaled Abuse of Stolen GitHub Tokens Stumbles, 25 Oct 2026
  2. The Hacker News — Gheist Uses Stolen GitHub Tokens to Steal Private Repository Secrets via Actions Logs, 26 Oct 2026
  3. GitHub Changelog — GitHub Actions holds potentially malicious workflows for approval, 28 Jul 2026
  4. GitHub Docs — Security hardening for GitHub Actions
  5. GitHub Docs — OpenID Connect
  6. CISA — KEV JSON feed catalog 2026.10.23
  7. GitGuardian — GhostAction returns, 7 Oct 2026 (distinct campaign)
  8. Huntress — M365 Token Spray and Replay Campaign, 22 Oct 2026
  9. RWP Ventures — LiteLLM Daily Top 2026-10-25
  10. RWP Ventures — Collabora CODE Daily Top 2026-10-24
  11. RWP Ventures — Arista VeloCloud Daily Top 2026-10-23