Skip to content

This tool is not affiliated with, endorsed by or sponsored by GitHub, Inc. or Microsoft Corporation. GitHub and GitHub Actions are trademarks of GitHub, Inc. Other names are trademarks of their respective owners.

Leaked cloud keys in GitHub Actions: the cloud pivot

AWS, Google Cloud or Azure keys leaked from GitHub Actions or a repo: contain the key, trace its use in the cloud audit logs, then replace keys with OIDC.

Published on 5 min read

TL;DR. Once a cloud key leaves GitHub (printed by a workflow, cloned in a repository's history, found by secret scanning), the GitHub investigation becomes a cloud investigation. Deactivate the key, but first note its ID and the exact time window. Search the cloud's own logs for every call made with it: CloudTrail for AWS, Cloud Audit Logs for Google Cloud, Activity and Entra ID sign-in logs for Azure. Replace stored keys with OIDC federation so that the next workflow compromise yields a short-lived, narrowly scoped token instead.

GitHub is rarely the attacker's final target. Repositories and Actions secrets hold the credentials of the systems that matter: production cloud accounts, registries and databases. The analyzer marks this handoff as a next hop. When the actions-secret-exfil rule sees AWS, Google Cloud or Azure credential names in a script that encodes or ships secrets, or when a secret-scanning alert concerns a cloud credential, the result links to the relevant cloud tool.

Where cloud keys leak from GitHub

SourceEvidence on the GitHub sideCovered in
Workflow prints or sends secretsRun log archive: encoder or curl in the step script, long encoded blob in the outputActions secrets leak
Key committed to a repository, then clonedgit.clone bursts, secret-scanning alert, push protection bypassRepository exfiltration
Environment protection removedenvironment.remove_protection_rule before a run that used the environmentBranch protection tampering
Self-hosted runner compromisedRunner host with an instance role or cached CLI credentialsSelf-hosted runner security

Secret-scanning alerts (secret_scanning_alert.create, secret_scanning_alert.public_leak) and push protection bypasses (secret_scanning_push_protection.bypass) are raised by the rules secret-leak-alert and push-protection-bypass. Drop the organization's secret-scanning alerts JSON next to the audit log to include them.

First: pin down the key and the window

Before you rotate, record:

  • The key identifier. For AWS, the access key ID (AKIA… for long-term user keys, ASIA… for temporary credentials). For Google Cloud, the service account email and key ID in the JSON. For Azure, the application (client) ID of the service principal and the secret or certificate ID.
  • The exposure start. The time of the malicious run or push, the clone, or the alert. The analyzer's finding gives the first-seen time in UTC.
  • Where it was valid. Which account, project or subscription, and which permissions it had.

Then deactivate or delete the key. In AWS, deactivating an access key lets you reactivate it if production breaks. Once you have confirmed nothing legitimate still depends on it, delete it.

AWS: CloudTrail

Search CloudTrail for the access key ID from the exposure start onwards. Event history and CloudTrail Lake can filter on the access key. Look for:

  • Identity checks that attackers typically run first (GetCallerIdentity), followed by enumeration (List*, Describe*, Get* in bursts).
  • Calls from IPs and user agents that do not match your CI (GitHub-hosted runners come from GitHub's published ranges. A laptop's aws-cli from a VPS is not them).
  • Persistence: CreateUser, CreateAccessKey, CreateLoginProfile, AttachUserPolicy, new roles or trust-policy changes.
  • Data access: S3 GetObject at volume, Secrets Manager or SSM Parameter Store reads.

The sibling AWS Forensics tool analyses CloudTrail exports the same way this site analyses GitHub: in the browser, nothing uploaded.

Google Cloud: Cloud Audit Logs

For a leaked service account key, filter Cloud Audit Logs on the service account as principal and look at Admin Activity and, where enabled, Data Access logs. Watch for new service account keys, IAM policy bindings, and access to Cloud Storage or Secret Manager. Continue with GCP Forensics.

Azure: Activity log and Entra ID

For a service principal secret, check the Entra ID service principal sign-in logs for the application ID, then the Activity log for what it changed: role assignments, new credentials on applications, and Key Vault access. Continue with Azure Forensics.

Replace keys with OIDC federation

Most of these incidents exist because a long-lived key sits in a GitHub secret. GitHub Actions can request a short-lived OIDC token for each job, and AWS, Google Cloud and Azure can trust it directly. See GitHub's OpenID Connect documentation and the OIDC federation glossary entry. GitHub's secure use reference recommends it for cloud deployments.

What changes for an attacker:

Stored access keyOIDC federation
LifetimeUntil someone rotates itMinutes to an hour (cloud-side session)
Usable outside the workflowYes, from anywhereOnly until it expires
ScopeWhatever the key's user hasA role whose trust policy can require a specific repository, branch or environment (sub claim)
Visible in logsKey IDRole session tied to the GitHub claims

OIDC is not a cure-all. A poisoned workflow running on an allowed branch still gets a valid token during the run. But the window shrinks from "until rotation" to "while the job runs", and trust conditions such as repo:ORG/REPO:environment:production block tokens requested from attacker branches.

Checklist

  • Record the key ID, the account and the exposure window. Then deactivate the key.
  • Pull the cloud logs for the window. Look for identity checks, enumeration, persistence and data access.
  • Rotate every other secret the same workflow could read (see the Actions article).
  • Remove what the attacker created in the cloud: users, keys, roles, functions, instances.
  • Move deployments to OIDC with trust conditions on repository and environment.

Related articles

Rogue or compromised GitHub self-hosted runners: the audit log events to check, host evidence in _diag, and how to scope and rebuild after an incident.
How GitHub Actions secrets leak despite *** masking: poisoned workflows, new branches, encoded output and third-party actions. The evidence to collect and read.
What the GitHub audit log does not record: 180-day and 7-day retention, plan limits for API and Git events, hidden IPs, no file contents or secret reads.

This tool is not affiliated with, endorsed by or sponsored by GitHub, Inc. or Microsoft Corporation. GitHub and GitHub Actions are trademarks of GitHub, Inc. Other names are trademarks of their respective owners.