GhostAction October 2026 Wave — GitHub Actions Secret Exfiltration Sentinel Hunts

Threat Overview

GitGuardian published a 13 October 2026 update to its 7 October GhostAction investigation; The Hacker News reported the expanded scale on 15 October. GitGuardian’s dataset shows attackers targeted over 30,000 repositories across roughly 3,000 users/organizations after compromising about 1,900 GitHub accounts. The October 8–9 payload inserted malicious GitHub Actions workflows that executed in CI and attempted to extract 3,174 secrets, including GitHub, cloud, and AI API credentials. The malicious workflow also scanned repository contents and full Git history, including context around AWS key IDs, then used curl to POST data to 193.32.204.199. GitGuardian reports GitHub began blocking these workflows on 9 October; later 10 and 12 October injections reportedly did not execute. The number of attempted extractions is not proof all secrets were successfully stolen. The attack relies on compromised maintainer credentials and repository write access, not a published GitHub platform CVE.

References

Impacted Systems

  • Platform: GitHub.com repositories and GitHub Actions CI/CD workflows, public and potentially private repositories reachable by compromised accounts. No GitHub software version/build or CVE is implicated.
  • Affected components: .github/workflows/*.yml, particularly security-audit.yml and github_actions_security.yml; workflow secrets, repository contents, and historical commits.
  • Prerequisite: Compromised maintainer account/token with repository write permission; workflow execution permissions and accessible secrets determine impact. Public GitHub-hosted runners generally do not generate an organization’s Sentinel endpoint events.
  • Exposure: Secrets accessible to CI or embedded in Git history, including cloud/API credentials. The attacker IP 193.32.204.199 is a reported campaign-specific exfiltration destination, not a universal indicator.
  • Fixed versions: Not applicable. GitGuardian says GitHub blocked the observed malicious workflow from 9 Oct 2026, but previously exposed secrets still require rotation. GitHub Enterprise Server is not specifically confirmed affected by the cited GitHub.com campaign.

Why this matters

One compromised developer identity can alter dozens of workflows, leak long-lived cloud keys, and create cross-customer exposure through shared CI/CD systems. This is particularly relevant to MSP/MSSP engineering teams, infrastructure-as-code repositories, and software supply chains.

Exploitation Status

Confirmed campaign and workflow execution. GitGuardian observed the October burst and states six injection batches executed; it reports later batches blocked by GitHub. 3,174 is attempted secrets extracted, not a confirmed count of successful exfiltrations. No confirmed exploitation of a GitHub platform vulnerability is claimed.

What this hunt looks for

Prepared indicator egress, workflow-file changes on monitored runners, git-history/secret-scanning process behavior, rare runner egress, GitHub CloudAppEvents workflow changes, AWS credential-use anomalies, and Linux Syslog fallback. These are queries for use where telemetry is ingested; no customer-specific execution or GitHub repository audit is claimed.

Required logs

Sentinel visibility depends on ingested GitHub audit/Defender for Cloud Apps activity, Defender endpoint telemetry for self-hosted CI runners, AWS CloudTrail, and forwarded Linux Syslog. GitHub-hosted Actions runner filesystem/process/network logs are not automatically in customer Sentinel. CloudAppEvents GitHub data is conditional on a configured connector and its schema. Absence of matches in these sources cannot clear GitHub repositories or unmonitored CI runners.

Hunt 01 — First pass — GhostAction exfiltration IP from onboarded CI runners or endpoints

DeviceNetworkEvents
| where TimeGenerated >= ago(45d)
| where RemoteIP == '193.32.204.199' or RemoteUrl contains '193.32.204.199'
| project TimeGenerated, DeviceName, RemoteIP, RemoteUrl, RemotePort, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessAccountName
| order by TimeGenerated desc

Hunt 02 — Endpoint files — unexpected GitHub Actions workflow creation or modification

DeviceFileEvents
| where TimeGenerated >= ago(30d)
| where FolderPath contains '.github' and FolderPath contains 'workflows'
| where FileName in~ ('security-audit.yml','github_actions_security.yml')
| project TimeGenerated, DeviceName, ActionType, FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine, SHA256
| order by TimeGenerated desc

Hunt 03 — Runner process — git history scanning combined with credential extraction commands

DeviceProcessEvents
| where TimeGenerated >= ago(30d)
| where FileName in~ ('bash','sh','git','grep','curl','python','python3','pwsh','powershell.exe')
| where ProcessCommandLine has_any ('git log -p','AKIA_CTX_START','fetch-depth: 0','193.32.204.199','PERSONAL_ACCESS_TOKEN')
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName, FolderPath
| order by TimeGenerated desc

Hunt 04 — Network — GitHub Actions runner contacting novel external IPs

let RunnerProcesses=dynamic(['Runner.Listener','Runner.Worker','runsvc.sh','bash','sh']);
let Recent=DeviceNetworkEvents
| where TimeGenerated >= ago(7d)
| where InitiatingProcessFileName in~ (RunnerProcesses)
| where isnotempty(RemoteIP) and not(ipv4_is_private(RemoteIP))
| summarize Hits=count(), LastSeen=max(TimeGenerated), Ports=make_set(RemotePort,10), Processes=make_set(InitiatingProcessFileName,10) by DeviceName, RemoteIP;
let Known=DeviceNetworkEvents
| where TimeGenerated between (ago(37d)..ago(7d))
| where InitiatingProcessFileName in~ (RunnerProcesses)
| summarize by DeviceName, RemoteIP;
Recent
| join kind=leftanti Known on DeviceName, RemoteIP
| order by Hits desc

Hunt 05 — Cloud App Events — GitHub workflow modifications where connector logs are ingested

CloudAppEvents
| where TimeGenerated >= ago(30d)
| extend App=tostring(column_ifexists('Application','')), Raw=tostring(column_ifexists('RawEventData','')), Obj=tostring(column_ifexists('ObjectName',''))
| where App contains 'GitHub' or Raw contains 'github.com'
| where Raw has_any ('security-audit.yml','github_actions_security.yml','.github/workflows','workflow_dispatch') or Obj has_any ('security-audit.yml','github_actions_security.yml')
| project TimeGenerated, Application, ActionType, AccountDisplayName, IPAddress, Obj, Raw
| order by TimeGenerated desc

Hunt 06 — AWS CloudTrail — anomalous secret retrieval or credential enumeration after potential CI compromise

AWSCloudTrail
| where TimeGenerated >= ago(30d)
| where EventName in~ ('GetSecretValue','GetParameter','GetParameters','ListSecrets','ListAccessKeys','CreateAccessKey','GetCallerIdentity')
| extend Principal=tostring(column_ifexists('UserIdentityArn','')), SourceIP=tostring(column_ifexists('SourceIpAddress',''))
| summarize Calls=count(), DistinctActions=dcount(EventName), Actions=make_set(EventName,15), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated) by Principal, SourceIP, bin(TimeGenerated,1h)
| where Calls >= 20 or DistinctActions >= 4
| order by Calls desc

Hunt 07 — Linux runner Syslog fallback — malicious workflow payload strings in forwarded audit/process logs

Syslog
| where TimeGenerated >= ago(30d)
| where SyslogMessage has_any ('193.32.204.199','security-audit.yml','github_actions_security.yml','AKIA_CTX_START')
| project TimeGenerated, Computer, ProcessName, SyslogMessage
| order by TimeGenerated desc

Detection Notes

  • Highest signal: Query 01 connection to reported exfiltration IP; query 02 unexpected workflow creation on self-hosted runners; query 05 GitHub audit activity if GitHub CloudAppEvents ingestion exists.
  • Important limitation: Most GitHub-hosted runners are ephemeral and external; DeviceProcessEvents and DeviceNetworkEvents in a customer workspace usually cannot observe their commands or exfiltration. No Sentinel match does not establish that workflows were clean.
  • CloudAppEvents: GitHub integration and event coverage are not confirmed for any customer in the supplied baseline. ActionType and RawEventData are connector-dependent; query 05 may return no results without ingestion.
  • AWS CloudTrail query 06 is a contextual pivot, not a GhostAction-specific signature. Secret access can be normal application behavior; correlate identities with known exposed repository secrets before escalation.
  • False positives: Git history scans, workflow edits, and high-volume secrets access can be legitimate CI work. IP matching is more specific but may be bypassed by attacker infrastructure rotation. GitHub’s blocking since 9 Oct reduces, but does not erase, earlier exposure.

Leave a Reply