Gheist Campaign Exploits Stolen GitHub Tokens to Exfiltrate Repository Secrets
A sophisticated automated campaign, dubbed 'Gheist' by cloud security firm **Wiz**, is actively leveraging stolen **GitHub** tokens to inject malicious workflows into repositories. These workflows are designed to print sensitive repository secrets into **GitHub Actions** logs, which attackers then swiftly download before deleting their traces. The campaign has successfully compromised private repositories and **GitHub Enterprise** environments, highlighting a significant supply chain security risk.
Cloud security company **Wiz** has uncovered an ongoing automated campaign, which they've named **Gheist**, that is exploiting stolen **GitHub** tokens to exfiltrate sensitive data from both public and private repositories. The attackers' method involves injecting malicious workflows into **GitHub Actions**, which then log a repository's secrets.

### How the Attack Unfolds
The **Gheist** campaign, tracked since September 15, operates by using stolen **GitHub** tokens to create new branches, typically named `ci-sync-` followed by six random characters. On these branches, a file named `.github/workflows/sync-check.yml` is committed. This workflow is designed to print the job's environment and all readable secrets, encoded in base32, into the **GitHub Actions** logs. While **GitHub** typically masks secrets in logs, encoding them bypasses this protection, allowing the full secret to be exposed.
Once the workflow completes, the attackers download the logs via the **GitHub API** and swiftly delete the run. This exfiltration method, occurring entirely within **GitHub's** infrastructure, makes it challenging to detect and block using traditional network-based security controls.
### Impact and Scope
**Wiz** has identified over 13,500 planted branches across more than 850 compromised accounts, ranging from personal projects to private repositories within enterprise organizations. A crucial finding is that a **GitHub** safeguard, implemented since July 28 to pause suspicious workflow runs, successfully stopped every public repository run checked by **Wiz**. However, this safeguard does not extend to private repositories or **GitHub Enterprise Server** environments, leaving them vulnerable.
In compromised enterprise environments, audit logs have shown the `gheist` user agent rapidly cycling through multiple user and automation tokens to clone private repositories before deploying the malicious workflow. In some cases, cloud credentials from the same organization were subsequently used to enumerate **AWS Secrets Manager**.
### Evolving Tactics and Connections
The **Gheist** campaign remains active and is continually evolving. **Wiz** reports that around October 19, a new variant began pushing a second job targeting self-hosted runners. This job attempts to search the runner machine for various credentials, including private keys, AWS instance role credentials, and **Kubernetes** service account tokens, though it appears to be buggy and has not yet been observed in successful runs.
The stolen tokens used in the **Gheist** campaign originate from various sources, including infostealer logs and tokens exposed in previous supply-chain attacks, such as the March compromise of the **Trivy** vulnerability scanner. Interestingly, some accounts involved in **Gheist** have also been linked to other malicious activities, including a campaign spreading malware disguised as cracked software and connections to the **PolinRider** malware, which researchers have associated with North Korean threat actors. Furthermore, 57 of the affected accounts were previously hit by **Megalodon**, another campaign that pushed secret-stealing workflows.
### How to Check Your Repositories
**Wiz** recommends the following checks for potential compromise:
* Look for branches named `ci-sync-` followed by six characters, where the only change is a new `.github/workflows/sync-check.yml` file with the commit message `ci: sync config`.
* In **GitHub** audit logs, search for workflow runs on `ci-sync-*` branches that were deleted within a minute of finishing, and for any activity from the user agent `gheist`.
* If your workflows use **OIDC** to sign in to a cloud provider, check cloud audit logs for role assumptions or token exchanges where the subject includes a `ci-sync-` branch. This is effective even without **GitHub** logs.
* On self-hosted runners, look for files named `.gdmp_pat`, `.gdmp_patg`, and `.gdmp_sweep`, and search for the string `gdmp-pivot` in job logs.
### Indicators of Compromise (IoCs)
* **User agent**: `gheist`
* **Branch pattern**: `^ci-sync-[0-9a-z]{6}$`
* **Commit message**: `ci: sync config`, adding only `.github/workflows/sync-check.yml`
* **String**: `toJSON(secrets) }}' | base32 -w 120`
* **String**: `===== gdmp-pivot:`
* **File**: `.gdmp_pat`
* **File**: `.gdmp_patg`
* **File**: `.gdmp_sweep`
* **Git blob SHA** (plain workflow): `f3da2b8b357dcda02fd455d314be2a95007516a6`
* **Git blob SHA** (timeout version): `d09535857a741bbb976bdc084a9a021713133291`
* **Git blob SHA** (separator version): `1dc5af9cce950aad1eb1546ecce8565b117540c4`
* **Git blob SHA** (self-hosted job version): `c665b778b2d822453293003e7ca0bbb2cb08e39d`
### What to Do If Compromised
If a `ci-sync` branch is found, **Wiz** advises the following immediate actions:
* Rotate every repository, organization, and environment secret that the affected repository could access.
* Revoke the tokens that pushed the malicious commits and thoroughly check the token owners' devices for infostealers.
* If a `ci-sync` branch executed on a self-hosted runner, treat the machine and its associated cloud instance role as fully compromised.