AWS Credentials Used from GitHub Actions and Non-CI/CD Infrastructure

edit
IMPORTANT: This documentation is no longer updated. Refer to Elastic's version policy and the latest documentation.

AWS Credentials Used from GitHub Actions and Non-CI/CD Infrastructure

edit

Detects AWS access keys that are used from both GitHub Actions CI/CD infrastructure and non-CI/CD infrastructure. This pattern indicates potential credential theft where an attacker who has stolen AWS credentials configured as GitHub Actions secrets and is using them from their own infrastructure.

Rule type: esql

Rule indices: None

Severity: high

Risk score: 73

Runs every: 1h

Searches indices from: now-7d (Date Math format, see also Additional look-back time)

Maximum alerts per execution: 100

References:

Tags:

  • Domain: Cloud
  • Data Source: AWS
  • Data Source: Amazon Web Services
  • Data Source: AWS CloudTrail
  • Data Source: AWS IAM
  • Use Case: Threat Detection
  • Tactic: Initial Access
  • Tactic: Lateral Movement
  • Resources: Investigation Guide

Version: 1

Rule authors:

  • Elastic

Rule license: Elastic License v2

Investigation guide

edit

Triage and analysis

Investigating AWS Credentials Used from GitHub Actions and Non-CI/CD Infrastructure

This rule detects when an AWS access key appears in CloudTrail from both GitHub Actions runners (identified by Microsoft ASN or the github-actions user agent string) and from infrastructure outside the expected CI/CD provider ASNs. This is a strong indicator that AWS credentials stored as GitHub repository or organization secrets have been exfiltrated and are being used by an attacker from their own infrastructure.

Possible investigation steps

  • Identify which GitHub repository owns the credential by cross-referencing the access key ID with your GitHub Actions workflow configurations and AWS IAM user/role assignments.
  • Review the suspicious source IPs and ASNs — residential ISPs, VPN providers, or budget hosting providers are high-confidence indicators of credential theft.
  • Check the actions performed from the suspicious source — sts:GetCallerIdentity followed by enumeration calls (ListBuckets, DescribeInstances, ListUsers) is a common attacker recon pattern after credential theft.
  • Review the user agent strings from the suspicious source — aws-cli or boto3 from a non-runner IP confirms manual/scripted usage outside CI/CD.
  • Check GitHub audit logs for recent workflow changes, new collaborators, or secret access events that could indicate how the credential was stolen.
  • Determine if the credential is a long-lived IAM user key or a temporary STS session — temporary credentials from AssumeRoleWithWebIdentity (OIDC) are less likely to be exfiltrated but still possible.

Response and remediation

  • Immediately rotate the compromised AWS access key in IAM and update the GitHub repository/org secret.
  • Review and revoke any resources created or modified by the suspicious source IP using CloudTrail event history filtered by the access key ID.
  • Audit the GitHub repository for signs of compromise — check for unauthorized workflow modifications, new secrets, or suspicious pull requests that could have exfiltrated the credential.
  • Implement OIDC-based authentication (aws-actions/configure-aws-credentials with role-to-assume) instead of long-lived access keys to eliminate the credential theft vector entirely.
  • If using OIDC, add IP condition policies to the IAM role trust policy to restrict AssumeRoleWithWebIdentity to known GitHub runner IP ranges.
  • Enable GitHub’s secret scanning and push protection to detect accidental credential exposure in code or logs.

Rule query

edit
from logs-aws.cloudtrail-* metadata _id, _version, _index

| WHERE event.dataset == "aws.cloudtrail"
  AND aws.cloudtrail.user_identity.access_key_id IS NOT NULL
  AND @timestamp >= NOW() - 7 days
  AND source.as.organization.name IS NOT NULL

// AWS API key used from github actions
| EVAL is_aws_github = user_agent.original LIKE "*aws-credentials-for-github-actions"

// non CI/CD related ASN
| EVAL is_not_cicd_infra = not source.as.organization.name IN ("Microsoft Corporation", "Amazon.com, Inc.", "Amazon Technologies Inc.", "Google LLC")

| STATS Esql.is_github_aws_key = MAX(CASE(is_aws_github, 1, 0)),
        Esql.has_suspicious_asn = MAX(CASE(is_not_cicd_infra, 1, 0)),
        Esql.last_seen_suspicious_asn = MAX(CASE(is_not_cicd_infra, @timestamp, NULL)),
        Esql.source_ip_values = VALUES(source.address),
        Esql.source_asn_values = VALUES(source.as.organization.name) BY aws.cloudtrail.user_identity.access_key_id, user.name, cloud.account.id

// AWS API key tied to a GH action used from unusual ASN (non CI/CD infra)
| WHERE Esql.is_github_aws_key == 1 AND  Esql.has_suspicious_asn == 1

        // avoid alert duplicates within 1h interval
        AND Esql.last_seen_suspicious_asn >= NOW() - 1 hour

| KEEP user.name, aws.cloudtrail.user_identity.access_key_id, Esql.*

Framework: MITRE ATT&CKTM