Cloud security firm Wiz has published an analysis of an automated campaign — tracked as Gheist — that is actively compromising GitHub organizations, including private repositories and GitHub Enterprise environments. The attack chain is deceptively simple: the adversary uses stolen GitHub access tokens to commit a malicious GitHub Actions workflow into a victim repository. When that workflow executes, it prints the repository's configured secrets into the Actions run logs in plaintext. The attackers then download the logs, delete the workflow run to erase the evidence, and walk away with credentials that often unlock cloud providers, package registries, and production infrastructure.
This is not a vulnerability in GitHub itself — it is a credential-abuse campaign that weaponizes a legitimate CI/CD feature. That distinction matters for defenders, because there is no patch to deploy. Your mitigation surface is token hygiene, workflow governance, audit log monitoring, and secret rotation. If your organization stores cloud keys, signing certificates, or deployment credentials as GitHub Actions secrets — and most engineering organizations do — you are in the blast radius.
Technical Analysis
Affected Platforms
- GitHub.com organizations with private repositories
- GitHub Enterprise Cloud and GitHub Enterprise Server environments
- Any repository using GitHub Actions secrets (repository-level, environment-level, or organization-level)
Attack Chain
Based on the Wiz analysis, the Gheist intrusion follows a consistent pattern:
-
Token acquisition. The campaign begins with already-stolen GitHub tokens — personal access tokens (PATs) or OAuth tokens harvested through prior compromises, malware infections on developer workstations, leaked tokens in public commits, or third-party breaches. The campaign is automated, suggesting attackers are feeding large token lists into validation and exploitation tooling.
-
Repository access validation. The stolen token is used to enumerate accessible repositories. Because PATs frequently carry broad scopes (
repo,workflow), a single compromised token often grants write access to multiple private repositories across an organization. -
Malicious workflow planting. The attacker commits a GitHub Actions workflow file (e.g., under
.github/workflows/) crafted to trigger immediately — typically onpushor viaworkflow_dispatch. The workflow's job steps read secrets from the runner context and echo them to stdout, which lands them in the Actions run logs. Common laundering tricks include base64-encoding or chunking secret values to evade GitHub's built-in log masking (GitHub automatically redacts exact secret string matches, so attackers obfuscate the output format). -
Log retrieval and evidence destruction. The attacker downloads the run logs via the API, then deletes the workflow run — a capability available via the Actions API — to remove the most obvious forensic artifact. The malicious workflow file itself may also be removed in a follow-up commit.
-
Secret monetization. Harvested secrets typically include cloud IAM keys (AWS, Azure, GCP), registry credentials (Docker Hub, npm, PyPI), database connection strings, and SSH keys — enabling downstream compromise far beyond the source repository.
Why This Works
- Over-scoped tokens: Classic PATs grant sweeping permissions with no repository granularity and often no expiration.
- Secrets-in-logs is a design tension: GitHub Actions runners receive secrets as environment variables. Any code that runs in a workflow can read them. GitHub's log masking only catches exact string matches; trivial encoding defeats it.
- Run deletion is a feature: Legitimate users delete noisy or sensitive workflow runs. Attackers exploit the same API to clean up.
- A safeguard gap: GitHub has a safeguard that pauses certain workflows (e.g., workflows from first-time contributors or new workflow files in some contexts), but Wiz's reporting indicates attacks have succeeded in private repositories and Enterprise environments — meaning tokens with sufficient privilege bypass those friction points entirely.
Exploitation Status
Confirmed active, in-the-wild exploitation. This is an automated campaign observed succeeding against real organizations, per Wiz. No CVE is associated with this activity — it is technique-based abuse of legitimate functionality, mapping to MITRE ATT&CK techniques including T1528 (Steal Application Access Token), T1552 (Unsecured Credentials), and T1078 (Valid Accounts).
Detection & Response
The highest-fidelity telemetry for this campaign lives in the GitHub audit log and the Actions API activity stream. If you are not shipping GitHub audit logs to your SIEM today, that is the first remediation item — everything below depends on it. Key audit log events to alert on: workflows.created_workflow, workflows.completed_workflow_run followed rapidly by run deletion, repo.actions_secret access events, and token-authenticated API activity from anomalous source IPs or user agents.
Sigma Rules
The following rules assume GitHub audit log / Actions telemetry ingested into a SIEM. Tune the logsource to your ingestion pipeline.
---
title: GitHub Actions Workflow Run Deleted Shortly After Completion
id: 3f8a2c71-9b4d-4e62-a15c-7d0e8f2a3b41
status: experimental
description: Detects a GitHub Actions workflow run being deleted within a short window of completion, consistent with Gheist campaign evidence-destruction behavior where attackers delete runs after harvesting secrets from logs.
references:
- https://thehackernews.com/2026/10/gheist-uses-stolen-github-tokens-to.html
- https://attack.mitre.org/techniques/T1070/
author: Security Arsenal
date: 2026/10/15
tags:
- attack.defense_evasion
- attack.t1070
logsource:
product: github
service: audit
detection:
selection:
action:
- 'workflows.delete_workflow_run'
- 'actions_workflow_run.delete'
filter_bot:
actor|contains:
- 'dependabot'
- 'github-actions'
- 'renovate'
condition: selection and not filter_bot
falsepositives:
- Developers manually cleaning up failed or sensitive workflow runs
- Automated retention/cleanup scripts — maintain an allowlist of known cleanup service accounts
level: high
---
title: New GitHub Actions Workflow Committed via Token Authentication
id: 8c1d4e92-2f7a-4b38-9d06-5a3c1e7f9b52
status: experimental
description: Detects creation of a new workflow file under .github/workflows where the actor authenticated via a personal access token or OAuth token rather than interactive SSO, a hallmark of the Gheist campaign's automated workflow planting.
references:
- https://thehackernews.com/2026/10/gheist-uses-stolen-github-tokens-to.html
- https://attack.mitre.org/techniques/T1078/
author: Security Arsenal
date: 2026/10/15
tags:
- attack.initial_access
- attack.t1078
- attack.t1528
logsource:
product: github
service: audit
detection:
selection:
action:
- 'workflows.created_workflow'
- 'repo.push'
file_path|contains:
- '.github/workflows/'
selection_token:
auth_type|contains:
- 'personal_access_token'
- 'oauth'
condition: selection and selection_token
falsepositives:
- Legitimate CI automation committing workflow templates — allowlist known automation accounts and source IPs
level: medium
---
title: GitHub Actions Run Log Downloaded by Non-Interactive Client
id: 5e7b3a14-6c9f-4d21-b8a3-2f6e9d4c7a83
status: experimental
description: Detects API-based download of GitHub Actions run logs from anomalous user agents or source IPs, consistent with Gheist attackers retrieving logs containing exfiltrated secrets.
references:
- https://thehackernews.com/2026/10/gheist-uses-stolen-github-tokens-to.html
- https://attack.mitre.org/techniques/T1552/
author: Security Arsenal
date: 2026/10/15
tags:
- attack.collection
- attack.credential_access
- attack.t1552
logsource:
product: github
service: audit
detection:
selection:
action|contains:
- 'workflow_run_logs'
- 'actions.logs_download'
filter_known:
user_agent|contains:
- 'GitHub Desktop'
- 'Mozilla'
condition: selection and not filter_known
falsepositives:
- Developers using gh CLI to debug failing runs — correlate with source IP and actor history before escalating
level: medium
KQL — Microsoft Sentinel / Defender
Assumes GitHub audit logs ingested via the GitHub connector or API into a GitHubAuditLog_CL custom table (adjust table and column names to your workspace). The query correlates workflow creation, run completion, log download, and run deletion by the same actor within a tight window — the Gheist kill chain in a single hunt.
// Hunt for Gheist-style kill chain: workflow created -> run deleted by same token-authenticated actor
let Lookback = 14d;
let SuspiciousActors = GitHubAuditLog_CL
| where TimeGenerated > ago(Lookback)
| where action_s in ("workflows.created_workflow", "workflows.delete_workflow_run")
| summarize Actions = make_set(action_s), EventCount = count(),
FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated),
SourceIPs = make_set(ip_s), Repos = make_set(repo_s)
by actor_s
| where Actions has "workflows.created_workflow" and Actions has "workflows.delete_workflow_run"
| where EventCount >= 2;
GitHubAuditLog_CL
| where TimeGenerated > ago(Lookback)
| where actor_s in~ (SuspiciousActors | project actor_s)
| project TimeGenerated, actor_s, action_s, repo_s, ip_s, user_agent_s, additional_fields_s
| order by actor_s asc, TimeGenerated asc;
// Supplementary: flag short-lived workflow runs (created and deleted within 60 minutes)
GitHubAuditLog_CL
| where TimeGenerated > ago(7d)
| where action_s == "workflows.created_workflow"
| join kind=inner (
GitHubAuditLog_CL
| where TimeGenerated > ago(7d)
| where action_s == "workflows.delete_workflow_run"
) on actor_s, repo_s
| where (TimeGenerated1 - TimeGenerated) < timespan(01:00:00)
| project WorkflowCreated = TimeGenerated, RunDeleted = TimeGenerated1, actor_s, repo_s, ip_s, ip_s1
| order by WorkflowCreated desc;
Velociraptor VQL — Developer Endpoint Hunt
Because Gheist begins with stolen tokens, hunt the upstream source: developer workstations where token stores (~/.git-credentials, GitHub CLI config, credential helper caches) are being read by unexpected processes — a common infostealer behavior.
-- Hunt for suspicious processes accessing GitHub credential stores on endpoints
-- Targets infostealer-style access to git credential files and gh CLI auth tokens
SELECT Pid, Name, CommandLine, Exe, Username, CreateTime
FROM pslist()
WHERE CommandLine =~ '(?i)git-credentials|gh\\/hosts.yml|\.config/gh|credential.helper'
AND NOT Name =~ '(?i)git|gh|credential-manager|code|devenv'
-- Enumerate git credential files and their recent access artifacts
SELECT FullPath, Size, Mtime, Atime
FROM glob(globs=['C:/Users/*/.git-credentials',
'C:/Users/*/.config/gh/hosts.yml',
'/home/*/.git-credentials',
'/home/*/.config/gh/hosts.yml'])
ORDER BY Atime DESC
Remediation Script — Bash
The following script audits a GitHub organization for indicators of Gheist activity using the GitHub API: recently deleted runs are not directly listed, but it surfaces recently created/modified workflow files by non-standard actors and lists recently active tokens. Run with a GitHub App or admin PAT that has audit log read scope.
#!/usr/bin/env bash
# Gheist exposure audit: suspicious workflows + audit log review
# Requires: gh CLI authenticated with an admin token, jq installed
set -euo pipefail
ORG="your-org-name"
DAYS=14
SINCE=$(date -u -d "${DAYS} days ago" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-${DAYS}d +%Y-%m-%dT%H:%M:%SZ)
echo "[*] Pulling audit log events for workflow lifecycle actions (last ${DAYS} days)..."
gh api "orgs/${ORG}/audit-log" --paginate \
-q ".[] | select(.created_at > \"${SINCE}\") | select(.action | test(\"workflow\")) | [.created_at, .actor, .action, .repo] | @tsv" \
| tee gheist_workflow_audit.tsv
echo ""
echo "[*] Flagging workflow run deletions (evidence destruction indicator)..."
grep -i "delete_workflow_run" gheist_workflow_audit.tsv || echo " None found in window."
echo ""
echo "[*] Scanning all repos for workflow files committed in the last ${DAYS} days..."
gh repo list "${ORG}" --limit 500 --json name -q '.[].name' | while read -r REPO; do
gh api "repos/${ORG}/${REPO}/commits" \
-q ".[] | select(.commit.author.date > \"${SINCE}\") | .sha" 2>/dev/null | while read -r SHA; do
gh api "repos/${ORG}/${REPO}/commits/${SHA}" \
-q ".files[]? | select(.filename | startswith(\".github/workflows/\")) | \"${REPO} " + .filename + \" " + .status" 2>/dev/null
done
done | tee gheist_recent_workflows.tsv
echo ""
echo "[*] ACTION ITEMS:"
echo " 1. Review gheist_recent_workflows.tsv — any workflow not traceable to a known PR/developer is suspect."
echo " 2. Rotate ALL Actions secrets in any repo with an unexplained workflow commit or deleted run."
echo " 3. Revoke and reissue PATs for any actor appearing in gheist_workflow_audit.tsv from an unexpected IP."
Remediation
Because this campaign abuses valid credentials rather than a software flaw, remediation is a credential and governance exercise. Prioritize in this order:
Immediate (next 24–72 hours):
- Hunt before you rotate. Pull your GitHub audit logs and run the queries above. Rotating secrets before identifying scope lets attackers keep un-rotated credentials and destroys your investigative window.
- Rotate secrets in any repository showing unexplained workflow commits, deleted runs, or anomalous log downloads. Assume anything readable by a workflow is compromised. Include downstream rotation: if an AWS key lived in a repo secret, rotate it in AWS and review CloudTrail for use from unknown principals.
- Revoke suspect tokens. Audit all active PATs and OAuth grants at the organization level. Kill any token with the
workflowscope that cannot be tied to a current, named purpose.
Short-term (this week):
- Migrate classic PATs to fine-grained PATs with per-repository scoping, least-privilege permissions, and mandatory expiration (90 days maximum for human users).
- Enforce organization-level token policies: require admin approval for fine-grained PATs and OAuth app access in GitHub Enterprise settings.
- Enable and ship audit log streaming (GitHub Enterprise supports streaming to Azure Event Hubs, Splunk, S3, and others) — without this telemetry, the detections above are impossible.
- Require environments with protection rules for high-value secrets. Environment-level secrets gated by required reviewers cannot be read by a workflow that an attacker triggers ad hoc — the deployment sits waiting for human approval.
Structural (this quarter):
- Eliminate long-lived secrets from Actions entirely where feasible. Move cloud authentication to OIDC federation (GitHub's native support for AWS, Azure, and GCP) so workflows exchange short-lived tokens instead of storing static keys. This single change collapses most of the Gheist value proposition.
- Restrict workflow creation. Use GitHub's Actions permissions settings to require approval for workflows from new contributors, and consider CODEOWNERS rules requiring security-team review on any change to
.github/workflows/. - Harden the upstream token source. Gheist starts with stolen tokens — deploy endpoint detection coverage for infostealer TTPs on developer workstations, enforce phishing-resistant MFA (FIDO2) on GitHub accounts, and scan for tokens committed to public repos.
Reference: Wiz's original analysis and GitHub's audit log documentation are the authoritative sources for this campaign. There is no vendor patch and no CISA KEV entry — the deadline is self-imposed, and the attackers are already automated.
Related Resources
Security Arsenal Healthcare Cybersecurity AlertMonitor Platform Book a SOC Assessment healthcare Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.