AWS S3 Rapid Bucket Posture API Calls from a Single Principal
Identifies when the same AWS principal, from the same source IP, successfully invokes read-only S3 control-plane APIs that reveal bucket posture across many buckets in a short period. This pattern can indicate automated reconnaissance or security scanning, similar to CSPM tools and post-compromise enumeration. The rule excludes AWS service principals, requires programmatic-style sessions (not Management Console credentials), and requires populated resource and identity fields so nulls do not skew cardinality.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2026/04/02"
3integration = ["aws"]
4maturity = "production"
5min_stack_comments = "aws.cloudtrail.session_credential_from_console field introduced in AWS integration version 4.6.0"
6min_stack_version = "9.2.0"
7updated_date = "2026/04/10"
8
9[rule]
10author = ["Elastic"]
11description = """
12Identifies when the same AWS principal, from the same source IP, successfully invokes read-only S3 control-plane APIs
13that reveal bucket posture across many buckets in a short period. This pattern can indicate automated reconnaissance or
14security scanning, similar to CSPM tools and post-compromise enumeration. The rule excludes AWS service principals,
15requires programmatic-style sessions (not Management Console credentials), and requires populated resource and identity
16fields so nulls do not skew cardinality.
17"""
18false_positives = [
19 """
20 Legitimate security scanners, CSPM products, compliance jobs, and inventory automation may call the same read-only
21 bucket APIs across many buckets quickly. Verify the principal ARN, source IP, user agent, and schedule against known
22 approved tooling before treating the activity as malicious.
23 """,
24]
25from = "now-6m"
26language = "esql"
27license = "Elastic License v2"
28name = "AWS S3 Rapid Bucket Posture API Calls from a Single Principal"
29note = """## Triage and analysis
30
31### Investigating AWS S3 Rapid Bucket Posture API Calls from a Single Principal
32
33This rule detects when the same AWS principal (`aws.cloudtrail.user_identity.arn`), from the same `source.ip`, successfully invokes read-only S3 control-plane APIs that reveal bucket posture across more than 15 distinct `aws.cloudtrail.resources.arn` values within a 10-second window.
34
35Security scanners, compliance tools, and post-compromise reconnaissance often walk many buckets quickly to map public access, policies, and versioning. Bursts of distinct buckets in seconds are less typical of one-off console administration or single-bucket troubleshooting. This could be indicative of reconnaissance as seen by threat actors like Team PCP.
36
37### Possible investigation steps
38
39**Identify the actor and session context**
40- **Actor ARN (`aws.cloudtrail.user_identity.arn`)**: Determine which IAM user, role, or federated principal performed the reads. Confirm whether this identity is approved for broad S3 read or security auditing. Unusual types or unfamiliar roles may warrant deeper review.
41- **Access key (`Esql.aws_cloudtrail_user_identity_access_key_id_values`)**: Identify which access key or temporary credential was used. Correlate with IAM last-used metadata for the key or role session.
42
43**Characterize the bucket sweep**
44- **Distinct bucket count (`Esql.bucket_arn_count_distinct`)**: Compare to normal baselines for this identity; values at or just above the threshold may still warrant review for new automation.
45- **Bucket ARNs (`Esql.aws_cloudtrail_resources_arn_values`)**: Identify which buckets were touched. Prioritize buckets that store logs, backups, credentials, or regulated data. Search the same time range for write or policy-change APIs (`PutBucket*`, `DeleteBucket*`) on the same buckets.
46
47**Analyze source and client**
48- **Source IP (`Esql.source_ip_values`)**: Map to corporate egress, a known runner or bastion, an EC2 instance, or an unfamiliar ASN. Compare with VPC Flow Logs or proxy logs when available.
49- **User agent (`Esql.user_agent_original_values`, `Esql.user_agent_name_values`)**: Identify the AWS CLI, Boto3, a specific scanner, or custom scripts. Unusual or minimal user agents may align with tooling and require investigation.
50
51**Correlate in time**
52- Query CloudTrail for the same `aws.cloudtrail.user_identity.arn` and `source.ip` within approximately ±30 minutes for follow-on patterns: `ListBuckets`, `GetObject`, `PutBucketPolicy`, `AssumeRole`, or IAM changes.
53- Check for overlapping alerts related to credential access, unusual geolocation, or new external bucket policy grants.
54
55### False positive analysis
56
57Legitimate causes can include:
58- **Security and compliance scanners** (for example CSPM or assessment tools) using API credentials with `s3:Get*` permissions across many buckets.
59- **Inventory or backup catalog tools** that enumerate bucket metadata for reporting.
60- **CI/CD or infrastructure-as-code validation** jobs that verify bucket settings across environments.
61
62Validate whether the principal is a documented service account, the IP belongs to known infrastructure, and the timing matches scheduled jobs. If behavior is expected, consider raising the distinct-bucket threshold, adding `user_agent` filters, or documenting exception identities.
63
64### Response and remediation
65
66**Contain**
67- If activity is unexpected, rotate or disable keys for the affected identity, revoke active role sessions where possible, and restrict the source IP at the network layer if it is not authorized.
68
69**Investigate**
70- Export CloudTrail for the window around `Esql.time_window_date_trunc` and review all S3 and IAM events for the same actor.
71- Review IAM policies attached to the principal for excessive `s3:Get*` or `s3:List*` scope.
72
73**Harden**
74- Enforce least privilege on S3 read APIs; use permission boundaries or service control policies where appropriate.
75- Ensure sensitive buckets are not unnecessarily reachable from the observed network context.
76- Document approved scanning accounts and tune the rule to reduce noise from those identities.
77
78### Additional information
79
80- [AWS Security Incident Response Guide](https://docs.aws.amazon.com/whitepapers/latest/aws-security-incident-response-guide/aws-security-incident-response-guide.pdf)
81- [AWS Incident Response Playbooks](https://github.com/aws-samples/aws-incident-response-playbooks/)
82- [AWS Customer Playbook Framework](https://github.com/aws-samples/aws-customer-playbook-framework)
83
84"""
85references = [
86 "https://kudelskisecurity.com/research/investigating-two-variants-of-the-trivy-supply-chain-compromise",
87]
88risk_score = 21
89rule_id = "a7577205-88a1-4a08-85d4-7b72a9a2e969"
90severity = "low"
91tags = [
92 "Domain: Cloud",
93 "Data Source: AWS",
94 "Data Source: Amazon Web Services",
95 "Data Source: AWS S3",
96 "Data Source: AWS CloudTrail",
97 "Use Case: Threat Detection",
98 "Tactic: Discovery",
99 "Tactic: Collection",
100 "Resources: Investigation Guide",
101]
102timestamp_override = "event.ingested"
103type = "esql"
104
105query = '''
106from logs-aws.cloudtrail-* metadata _id, _version, _index
107| eval Esql.time_window_date_trunc = date_trunc(10 seconds, @timestamp)
108
109| where
110 data_stream.dataset == "aws.cloudtrail"
111 and event.provider == "s3.amazonaws.com"
112 and event.outcome == "success"
113 and event.action in (
114 "GetBucketAcl",
115 "GetBucketPublicAccessBlock",
116 "GetBucketPolicy",
117 "GetBucketPolicyStatus",
118 "GetBucketVersioning"
119 )
120 and aws.cloudtrail.user_identity.type != "AWSService"
121 and source.ip IS NOT NULL
122 and aws.cloudtrail.resources.arn IS NOT NULL
123 and aws.cloudtrail.user_identity.arn IS NOT NULL
124 and aws.cloudtrail.session_credential_from_console IS NULL
125
126| keep
127 @timestamp,
128 Esql.time_window_date_trunc,
129 event.action,
130 aws.cloudtrail.user_identity.arn,
131 aws.cloudtrail.user_identity.type,
132 aws.cloudtrail.user_identity.access_key_id,
133 source.ip,
134 aws.cloudtrail.resources.arn,
135 cloud.account.id,
136 cloud.region,
137 user_agent.original,
138 source.as.organization.name,
139 data_stream.namespace
140
141| stats
142 Esql.bucket_arn_count_distinct = count_distinct(aws.cloudtrail.resources.arn),
143 Esql.aws_cloudtrail_resources_arn_values = VALUES(aws.cloudtrail.resources.arn),
144 Esql.event_action_values = VALUES(event.action),
145 Esql.timestamp_values = VALUES(@timestamp),
146 Esql.aws_cloudtrail_user_identity_type_values = VALUES(aws.cloudtrail.user_identity.type),
147 Esql.aws_cloudtrail_user_identity_access_key_id_values = VALUES(aws.cloudtrail.user_identity.access_key_id),
148 Esql.cloud_account_id_values = VALUES(cloud.account.id),
149 Esql.cloud_region_values = VALUES(cloud.region),
150 Esql.user_agent_original_values = VALUES(user_agent.original),
151 Esql.source_as_organization_name_values = VALUES(source.as.organization.name),
152 Esql.data_stream_namespace_values = VALUES(data_stream.namespace)
153 by Esql.time_window_date_trunc, aws.cloudtrail.user_identity.arn, source.ip
154
155| where Esql.bucket_arn_count_distinct > 15
156'''
157
158
159[[rule.threat]]
160framework = "MITRE ATT&CK"
161[[rule.threat.technique]]
162id = "T1526"
163name = "Cloud Service Discovery"
164reference = "https://attack.mitre.org/techniques/T1526/"
165
166[[rule.threat.technique]]
167id = "T1580"
168name = "Cloud Infrastructure Discovery"
169reference = "https://attack.mitre.org/techniques/T1580/"
170
171[[rule.threat.technique]]
172id = "T1619"
173name = "Cloud Storage Object Discovery"
174reference = "https://attack.mitre.org/techniques/T1619/"
175
176
177[rule.threat.tactic]
178id = "TA0007"
179name = "Discovery"
180reference = "https://attack.mitre.org/tactics/TA0007/"
181[[rule.threat]]
182framework = "MITRE ATT&CK"
183[[rule.threat.technique]]
184id = "T1530"
185name = "Data from Cloud Storage"
186reference = "https://attack.mitre.org/techniques/T1530/"
187
188
189[rule.threat.tactic]
190id = "TA0009"
191name = "Collection"
192reference = "https://attack.mitre.org/tactics/TA0009/"
193
194[rule.investigation_fields]
195field_names = [
196 "Esql.bucket_arn_count_distinct",
197 "Esql.time_window_date_trunc",
198 "aws.cloudtrail.user_identity.arn",
199 "source.ip",
200 "Esql.aws_cloudtrail_resources_arn_values",
201 "Esql.event_action_values",
202 "Esql.aws_cloudtrail_user_identity_type_values",
203 "Esql.aws_cloudtrail_user_identity_access_key_id_values",
204 "Esql.cloud_account_id_values",
205 "Esql.cloud_region_values",
206 "Esql.user_agent_original_values",
207 "Esql.source_as_organization_name_values",
208 "Esql.data_stream_namespace_values",
209]
Triage and analysis
Investigating AWS S3 Rapid Bucket Posture API Calls from a Single Principal
This rule detects when the same AWS principal (aws.cloudtrail.user_identity.arn), from the same source.ip, successfully invokes read-only S3 control-plane APIs that reveal bucket posture across more than 15 distinct aws.cloudtrail.resources.arn values within a 10-second window.
Security scanners, compliance tools, and post-compromise reconnaissance often walk many buckets quickly to map public access, policies, and versioning. Bursts of distinct buckets in seconds are less typical of one-off console administration or single-bucket troubleshooting. This could be indicative of reconnaissance as seen by threat actors like Team PCP.
Possible investigation steps
Identify the actor and session context
- Actor ARN (
aws.cloudtrail.user_identity.arn): Determine which IAM user, role, or federated principal performed the reads. Confirm whether this identity is approved for broad S3 read or security auditing. Unusual types or unfamiliar roles may warrant deeper review. - Access key (
Esql.aws_cloudtrail_user_identity_access_key_id_values): Identify which access key or temporary credential was used. Correlate with IAM last-used metadata for the key or role session.
Characterize the bucket sweep
- Distinct bucket count (
Esql.bucket_arn_count_distinct): Compare to normal baselines for this identity; values at or just above the threshold may still warrant review for new automation. - Bucket ARNs (
Esql.aws_cloudtrail_resources_arn_values): Identify which buckets were touched. Prioritize buckets that store logs, backups, credentials, or regulated data. Search the same time range for write or policy-change APIs (PutBucket*,DeleteBucket*) on the same buckets.
Analyze source and client
- Source IP (
Esql.source_ip_values): Map to corporate egress, a known runner or bastion, an EC2 instance, or an unfamiliar ASN. Compare with VPC Flow Logs or proxy logs when available. - User agent (
Esql.user_agent_original_values,Esql.user_agent_name_values): Identify the AWS CLI, Boto3, a specific scanner, or custom scripts. Unusual or minimal user agents may align with tooling and require investigation.
Correlate in time
- Query CloudTrail for the same
aws.cloudtrail.user_identity.arnandsource.ipwithin approximately ±30 minutes for follow-on patterns:ListBuckets,GetObject,PutBucketPolicy,AssumeRole, or IAM changes. - Check for overlapping alerts related to credential access, unusual geolocation, or new external bucket policy grants.
False positive analysis
Legitimate causes can include:
- Security and compliance scanners (for example CSPM or assessment tools) using API credentials with
s3:Get*permissions across many buckets. - Inventory or backup catalog tools that enumerate bucket metadata for reporting.
- CI/CD or infrastructure-as-code validation jobs that verify bucket settings across environments.
Validate whether the principal is a documented service account, the IP belongs to known infrastructure, and the timing matches scheduled jobs. If behavior is expected, consider raising the distinct-bucket threshold, adding user_agent filters, or documenting exception identities.
Response and remediation
Contain
- If activity is unexpected, rotate or disable keys for the affected identity, revoke active role sessions where possible, and restrict the source IP at the network layer if it is not authorized.
Investigate
- Export CloudTrail for the window around
Esql.time_window_date_truncand review all S3 and IAM events for the same actor. - Review IAM policies attached to the principal for excessive
s3:Get*ors3:List*scope.
Harden
- Enforce least privilege on S3 read APIs; use permission boundaries or service control policies where appropriate.
- Ensure sensitive buckets are not unnecessarily reachable from the observed network context.
- Document approved scanning accounts and tune the rule to reduce noise from those identities.
Additional information
References
Related rules
- AWS API Activity from Uncommon S3 Client by Rare User
- AWS Account Discovery By Rare User
- AWS S3 Bucket Enumeration or Brute Force
- AWS S3 Bucket Policy Added to Allow Public Access
- AWS S3 Bucket Policy Added to Share with External Account