← Rule library
high KQL AWS
S3 Bucket Policy Opened to Public
Public-ACL or wildcard-principal changes on a bucket. Usually a misconfiguration, occasionally staged exfiltration.
Rule source
// S3 Bucket Policy Opened to Public
// T1530 - Data from Cloud Storage
// Usually a misconfiguration, occasionally staged exfiltration.
// Either way you want it in minutes, not at the next audit.
let approved_public_buckets = dynamic([
"detectionops-public-assets",
"detectionops-docs-site"
]);
AWSCloudTrail
| where EventName in ("PutBucketPolicy", "PutBucketAcl", "DeletePublicAccessBlock")
| where isempty(ErrorCode)
| extend Params = parse_json(RequestParameters)
| extend BucketName = tostring(Params.bucketName)
| extend PolicyText = tostring(Params.bucketPolicy)
| where PolicyText has_any ('"Principal":"*"', '"AWS":"*"')
or tostring(Params.x_amz_acl) has_any ("public-read", "public-read-write")
or EventName == "DeletePublicAccessBlock"
| where BucketName !in (approved_public_buckets)
| project
TimeGenerated,
EventName,
BucketName,
Actor = UserIdentityArn,
SourceIpAddress,
AWSRegion
| order by TimeGenerated desc Required telemetry
AWS CloudTrail S3 management events
Confirm this source is arriving before you judge the rule. A detection built on telemetry you do not collect looks identical to one that simply never fires.
Known false positives
- Intentional static-website buckets - maintain an allowlist by name
- CDN origin configuration during initial setup
Validation
Create and immediately revert a public bucket in the sandbox account
Re-run quarterly. Rules decay because the environment moves underneath them - agent upgrades, schema changes and config edits all break detections silently.