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:GetCallerIdentityfollowed 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-cliorboto3from 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-credentialswithrole-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
AssumeRoleWithWebIdentityto 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
- AWS IAM Long-Term Access Key First Seen from Source IP
- AWS IAM Long-Term Access Key Correlated with Elevated Detection Alerts
- AWS Rare Source AS Organization Activity
- AWS Access Token Used from Multiple Addresses
- AWS Account Discovery By Rare User