GhostAction GitHub Actions Secret Exfiltration — Sentinel Hunts

Threat Overview

StepSecurity and Socket published new research on October 9, 2026 describing an active GhostAction wave in which compromised legitimate GitHub maintainer identities pushed apparently benign `security-audit.yml` / `github_actions_security.yml` workflows into hundreds of repositories on October 8. The workflows trigger on pushes or manual dispatch, enumerate configured GitHub Actions secrets and mine the working tree and full Git history for cloud, AI, and SaaS credentials, then POST results to 193.32.204.199 over HTTP. StepSecurity verified that the `uber/athenadriver` malicious workflow ran and received an acknowledgement from the attacker server. This is a confirmed supply-chain credential-exfiltration operation, not an unproven exploit hypothesis. The underlying credential-theft campaign dates to 2025, but the October 2026 wave introduces full-history mining and new mass compromises.

References

Impacted Systems

  • **Vendor/product:** GitHub repositories and **GitHub Actions** workflows (GitHub-hosted or self-hosted runners); GitHub Enterprise Cloud audit ingestion is optional.
  • **Affected scope:** Repositories receiving a malicious `.github/workflows/security-audit.yml`, `github_actions_security.yml`, or `security-check.yml` file; **no GitHub software version vulnerability is alleged**.
  • **Prerequisites:** Attacker controls a maintainer credential with workflow-write capability; Actions execution is permitted; secrets or credential-bearing Git history are accessible to the workflow.
  • **Exposed assets:** CI/CD secrets, publishing credentials, AWS/cloud keys, AI provider API keys, GitHub/GitLab tokens, repository history, and inherited forks.
  • **Fixed versions:** Not applicable; remediation is workflow removal, credential revocation, and repository/runner policy hardening.

Why this matters

A compromised maintainer can silently inject CI/CD exfiltration into many repositories and steal publishing tokens, cloud credentials, and historic secrets that developers believe were deleted. GitHub-hosted runners are usually outside an MSSP's endpoint/network visibility.

Exploitation Status

**Confirmed:** StepSecurity observed malicious pushes to 27 repositories under `kitao` and 318 under `henrywoo` on 2026-10-08, and validated an exfiltration POST acknowledged in an Actions run. **Socket research:** more than 500 accounts and tens of thousands of repositories were identified in the broader wave by October 9 (count subject to change). **Not established:** malicious package publication from the compromised publishing tokens as of the source publication; customer repository exposure is unverified.

What this hunt looks for

GitHubAuditLogsV3_CL / GitHubAuditLogsV2_CL if GitHub Enterprise audit logs are actually ingested; DeviceProcessEvents/DeviceNetworkEvents or SecurityEvent/Syslog only for **customer-managed self-hosted runners**; CommonSecurityLog only if runner traffic traverses monitored egress; AWSCloudTrail as a conditional follow-on credential-use hunt.

Required logs

AWSCloudTrail, CommonSecurityLog, DeviceNetworkEvents, DeviceProcessEvents, GitHubAuditLogsV2_CL, GitHubAuditLogsV3_CL, SecurityEvent, Syslog

Hunt 1: First pass — GitHub Enterprise audit events referencing malicious workflows (V3)

GitHubAuditLogsV3_CL
| where TimeGenerated >= ago(30d)
| extend Raw=tostring(pack_all())
| where Raw contains "security-audit.yml" or Raw contains "github_actions_security.yml" or Raw contains "security-check.yml" or Raw contains "Add security audit workflow"
| project TimeGenerated, Raw
| order by TimeGenerated desc

Hunt 2: GitHub Enterprise audit legacy V2 — suspicious workflow and dispatch

GitHubAuditLogsV2_CL
| where TimeGenerated >= ago(30d)
| extend Raw=tostring(pack_all())
| where Raw contains "security-audit.yml" or Raw contains "github_actions_security.yml" or Raw contains "workflow_dispatch" or Raw contains "security-check.yml"
| project TimeGenerated, Raw
| order by TimeGenerated desc

Hunt 3: Runner endpoint — git history sweep combined with curl or secret patterns

DeviceProcessEvents
| where TimeGenerated >= ago(30d)
| where ProcessCommandLine contains "git log -p --all" or ProcessCommandLine contains "AKIA_CTX_START" or (FileName in~ ("curl","curl.exe") and ProcessCommandLine contains "193.32.204.199")
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine, FolderPath
| order by TimeGenerated desc

Hunt 4: Runner/network — confirmed GhostAction exfiltration endpoint

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

Hunt 5: Firewall/proxy — raw-IP HTTP exfiltration and workflow receiver

CommonSecurityLog
| where TimeGenerated >= ago(30d)
| extend Uri=tostring(column_ifexists("RequestURL",""))
| where DestinationIP == "193.32.204.199" or Uri contains "193.32.204.199" or Uri contains "/api/workflow/receive?inj="
| project TimeGenerated, SourceIP, DestinationIP, DestinationPort, Uri, DeviceAction, DeviceVendor, DeviceProduct
| order by TimeGenerated desc

Hunt 6: Self-hosted runner — Linux command traces in Syslog

Syslog
| where TimeGenerated >= ago(30d)
| where SyslogMessage contains "AKIA_CTX_START" or SyslogMessage contains "193.32.204.199" or SyslogMessage contains "git log -p --all" or SyslogMessage contains "security-audit.yml"
| project TimeGenerated, Computer, ProcessName, SyslogMessage
| order by TimeGenerated desc

Hunt 7: Self-hosted Windows runner — process creation fallback

SecurityEvent
| where TimeGenerated >= ago(30d) and EventID == 4688
| extend Cmd=tostring(column_ifexists("CommandLine","")), Proc=tostring(column_ifexists("NewProcessName",""))
| where Cmd contains "193.32.204.199" or Cmd contains "git log -p --all" or Cmd contains "AKIA_CTX_START"
| project TimeGenerated, Computer, Account, Proc, Cmd
| order by TimeGenerated desc

Hunt 8: AWS follow-on — suspicious cloud API activity after possible secret theft

AWSCloudTrail
| where TimeGenerated >= ago(7d)
| extend Event=tostring(column_ifexists("EventName","")), Src=tostring(column_ifexists("SourceIpAddress","")), User=tostring(column_ifexists("UserIdentityArn",""))
| where Event in~ ("CreateAccessKey","CreateUser","AttachUserPolicy","PutUserPolicy","AssumeRole","GetSecretValue","ListSecrets","CreateLoginProfile")
| summarize Actions=count(), Events=make_set(Event,15), Sources=make_set(Src,15) by User, bin(TimeGenerated,1h)
| where Actions >= 3
| order by Actions desc

Detection Notes

**Highest signal:** direct changes to named malicious workflows, GitHub Actions runner POST to `193.32.204.199`, or commands containing `AKIA_CTX_START`/`git log -p –all` with exfil. **Caveats:** GitHub audit records may show commit events but not workflow file contents; the exact GitHub connector may use V2 or V3 tables; most GitHub-hosted runners do not emit endpoint logs to customer Sentinel. A clean Sentinel search cannot exclude a malicious workflow on GitHub. The AWSCloudTrail hunt is a follow-on hypothesis, not an actor-specific signature.

Visibility is limited to ingested Microsoft Sentinel tables and retention; a clean result does not establish absence of compromise. Queries have not been executed against customer workspaces.

Leave a Reply