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

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.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/04/21"
  3integration = ["aws"]
  4maturity = "production"
  5updated_date = "2026/04/21"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Detects AWS access keys that are used from both GitHub Actions CI/CD infrastructure and non-CI/CD infrastructure.
 11This pattern indicates potential credential theft where an attacker who has stolen AWS credentials configured as GitHub
 12Actions secrets and is using them from their own infrastructure.
 13"""
 14false_positives = [
 15    """
 16    AWS credentials legitimately shared between GitHub Actions and another Microsoft/Azure service
 17    may trigger this rule. Verify whether the non-CI/CD source IP is expected for the workload.
 18    """,
 19    """
 20    GitHub Actions self-hosted runners running on non-Microsoft/Amazon/Google infrastructure will
 21    appear as suspicious. Add the ASN of your self-hosted runner infrastructure to the is_cicd_infra
 22    allowlist.
 23    """,
 24]
 25from = "now-7d"
 26interval = "1h"
 27language = "esql"
 28license = "Elastic License v2"
 29name = "AWS Credentials Used from GitHub Actions and Non-CI/CD Infrastructure"
 30note = """## Triage and analysis
 31
 32### Investigating AWS Credentials Used from GitHub Actions and Non-CI/CD Infrastructure
 33
 34This rule detects when an AWS access key appears in CloudTrail from both GitHub Actions runners
 35(identified by Microsoft ASN or the `github-actions` user agent string) and from infrastructure
 36outside the expected CI/CD provider ASNs. This is a strong indicator that AWS credentials stored
 37as GitHub repository or organization secrets have been exfiltrated and are being used by an
 38attacker from their own infrastructure.
 39
 40### Possible investigation steps
 41
 42- Identify which GitHub repository owns the credential by cross-referencing the access key ID with
 43  your GitHub Actions workflow configurations and AWS IAM user/role assignments.
 44- Review the suspicious source IPs and ASNs — residential ISPs, VPN providers, or budget hosting
 45  providers are high-confidence indicators of credential theft.
 46- Check the actions performed from the suspicious source — `sts:GetCallerIdentity` followed by
 47  enumeration calls (`ListBuckets`, `DescribeInstances`, `ListUsers`) is a common attacker recon
 48  pattern after credential theft.
 49- Review the user agent strings from the suspicious source — `aws-cli` or `boto3` from a non-runner
 50  IP confirms manual/scripted usage outside CI/CD.
 51- Check GitHub audit logs for recent workflow changes, new collaborators, or secret access events
 52  that could indicate how the credential was stolen.
 53- Determine if the credential is a long-lived IAM user key or a temporary STS session — temporary
 54  credentials from `AssumeRoleWithWebIdentity` (OIDC) are less likely to be exfiltrated but still
 55  possible.
 56
 57### Response and remediation
 58
 59- Immediately rotate the compromised AWS access key in IAM and update the GitHub repository/org secret.
 60- Review and revoke any resources created or modified by the suspicious source IP using CloudTrail
 61  event history filtered by the access key ID.
 62- Audit the GitHub repository for signs of compromise — check for unauthorized workflow modifications,
 63  new secrets, or suspicious pull requests that could have exfiltrated the credential.
 64- Implement OIDC-based authentication (`aws-actions/configure-aws-credentials` with `role-to-assume`)
 65  instead of long-lived access keys to eliminate the credential theft vector entirely.
 66- If using OIDC, add IP condition policies to the IAM role trust policy to restrict
 67  `AssumeRoleWithWebIdentity` to known GitHub runner IP ranges.
 68- Enable GitHub's secret scanning and push protection to detect accidental credential exposure in
 69  code or logs.
 70"""
 71references = [
 72    "https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services",
 73    "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html",
 74]
 75risk_score = 73
 76rule_id = "b8c7d6e5-f4a3-4b2c-9d8e-7f6a5b4c3d2e"
 77severity = "high"
 78tags = [
 79    "Domain: Cloud",
 80    "Data Source: AWS",
 81    "Data Source: Amazon Web Services",
 82    "Data Source: AWS CloudTrail",
 83    "Data Source: AWS IAM",
 84    "Use Case: Threat Detection",
 85    "Tactic: Initial Access",
 86    "Tactic: Lateral Movement",
 87    "Resources: Investigation Guide",
 88]
 89timestamp_override = "event.ingested"
 90type = "esql"
 91
 92query = '''
 93from logs-aws.cloudtrail-* metadata _id, _version, _index
 94
 95| WHERE event.dataset == "aws.cloudtrail"
 96  AND aws.cloudtrail.user_identity.access_key_id IS NOT NULL
 97  AND @timestamp >= NOW() - 7 days
 98  AND source.as.organization.name IS NOT NULL
 99
100// AWS API key used from github actions 
101| EVAL is_aws_github = user_agent.original LIKE "*aws-credentials-for-github-actions"
102
103// non CI/CD related ASN 
104| EVAL is_not_cicd_infra = not source.as.organization.name IN ("Microsoft Corporation", "Amazon.com, Inc.", "Amazon Technologies Inc.", "Google LLC")
105
106| STATS Esql.is_github_aws_key = MAX(CASE(is_aws_github, 1, 0)),
107        Esql.has_suspicious_asn = MAX(CASE(is_not_cicd_infra, 1, 0)),
108        Esql.last_seen_suspicious_asn = MAX(CASE(is_not_cicd_infra, @timestamp, NULL)),
109        Esql.source_ip_values = VALUES(source.address), 
110        Esql.source_asn_values = VALUES(source.as.organization.name) BY aws.cloudtrail.user_identity.access_key_id, user.name, cloud.account.id
111
112// AWS API key tied to a GH action used from unusual ASN (non CI/CD infra)
113| WHERE Esql.is_github_aws_key == 1 AND  Esql.has_suspicious_asn == 1 
114
115        // avoid alert duplicates within 1h interval
116        AND Esql.last_seen_suspicious_asn >= NOW() - 1 hour
117
118| KEEP user.name, aws.cloudtrail.user_identity.access_key_id, Esql.*
119'''
120
121[rule.investigation_fields]
122field_names = [
123    "aws.cloudtrail.user_identity.access_key_id",
124    "user.name"
125]
126
127[[rule.threat]]
128framework = "MITRE ATT&CK"
129
130[[rule.threat.technique]]
131id = "T1078"
132name = "Valid Accounts"
133reference = "https://attack.mitre.org/techniques/T1078/"
134
135[[rule.threat.technique.subtechnique]]
136id = "T1078.004"
137name = "Cloud Accounts"
138reference = "https://attack.mitre.org/techniques/T1078/004/"
139
140[rule.threat.tactic]
141id = "TA0001"
142name = "Initial Access"
143reference = "https://attack.mitre.org/tactics/TA0001/"
144
145
146[[rule.threat]]
147framework = "MITRE ATT&CK"
148
149[[rule.threat.technique]]
150id = "T1550"
151name = "Use Alternate Authentication Material"
152reference = "https://attack.mitre.org/techniques/T1550/"
153
154[[rule.threat.technique.subtechnique]]
155id = "T1550.001"
156name = "Application Access Token"
157reference = "https://attack.mitre.org/techniques/T1550/001/"
158
159[rule.threat.tactic]
160id = "TA0008"
161name = "Lateral Movement"
162reference = "https://attack.mitre.org/tactics/TA0008/"

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.

References

Related rules

to-top