← Back to Explore
elastichighTTP
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.
Detection Query
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.*
Author
Elastic
Created
2026/04/21
Data Sources
AWSAmazon Web ServicesAWS CloudTrailAWS IAM
References
Tags
Domain: CloudData Source: AWSData Source: Amazon Web ServicesData Source: AWS CloudTrailData Source: AWS IAMUse Case: Threat DetectionTactic: Initial AccessTactic: Lateral MovementResources: Investigation Guide
Raw Content
[metadata]
creation_date = "2026/04/21"
integration = ["aws"]
maturity = "production"
updated_date = "2026/04/21"
[rule]
author = ["Elastic"]
description = """
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.
"""
false_positives = [
"""
AWS credentials legitimately shared between GitHub Actions and another Microsoft/Azure service
may trigger this rule. Verify whether the non-CI/CD source IP is expected for the workload.
""",
"""
GitHub Actions self-hosted runners running on non-Microsoft/Amazon/Google infrastructure will
appear as suspicious. Add the ASN of your self-hosted runner infrastructure to the is_cicd_infra
allowlist.
""",
]
from = "now-7d"
interval = "1h"
language = "esql"
license = "Elastic License v2"
name = "AWS Credentials Used from GitHub Actions and Non-CI/CD Infrastructure"
note = """## 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 = [
"https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services",
"https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html",
]
risk_score = 73
rule_id = "b8c7d6e5-f4a3-4b2c-9d8e-7f6a5b4c3d2e"
severity = "high"
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",
]
timestamp_override = "event.ingested"
type = "esql"
query = '''
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.*
'''
[rule.investigation_fields]
field_names = [
"aws.cloudtrail.user_identity.access_key_id",
"user.name"
]
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1078"
name = "Valid Accounts"
reference = "https://attack.mitre.org/techniques/T1078/"
[[rule.threat.technique.subtechnique]]
id = "T1078.004"
name = "Cloud Accounts"
reference = "https://attack.mitre.org/techniques/T1078/004/"
[rule.threat.tactic]
id = "TA0001"
name = "Initial Access"
reference = "https://attack.mitre.org/tactics/TA0001/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1550"
name = "Use Alternate Authentication Material"
reference = "https://attack.mitre.org/techniques/T1550/"
[[rule.threat.technique.subtechnique]]
id = "T1550.001"
name = "Application Access Token"
reference = "https://attack.mitre.org/techniques/T1550/001/"
[rule.threat.tactic]
id = "TA0008"
name = "Lateral Movement"
reference = "https://attack.mitre.org/tactics/TA0008/"