Skip to main content

Command Palette

Search for a command to run...

Securing S3 Bucket Policies: Public Access, Conditions, and Common Mistakes

Updated
2 min read
S
AI-Powered security analysis for AWS IAM policies, CloudFormation templates, and costs. Web app + CLI + VS Code extension + GitHub Action + CDK Guard. Try free at shieldly.io

S3 bucket policies are written once and forgotten. They survive team changes, architecture pivots, and migration projects — and they accumulate permissions that nobody intended to leave open. S3 misconfigurations have been behind some of the largest cloud data breaches on record.

Why S3 Bucket Policies Matter

Bucket policies are resource-based policies attached to the bucket itself. They can grant access to principals that have no IAM permissions at all — including anonymous callers — if the policy allows it. A single misconfigured statement can override months of careful IAM work.

The Three Most Dangerous Patterns

Principal: * with no condition. An unconditioned wildcard principal means any AWS account, any IAM entity, and any unauthenticated caller can invoke the allowed actions. On a public S3 endpoint this is the open internet.

Missing s3:SecureTransport condition. Without Condition: Bool: aws:SecureTransport: true on any Allow statement, the policy permits access over unencrypted HTTP. Credentials and data travel in plaintext.

Overly broad Action grants. s3:* includes s3:DeleteObject, s3:PutBucketPolicy, and s3:DeleteBucket. A policy intended to share read access becomes a full-control grant.

S3 Block Public Access Interaction

Block Public Access settings at the account and bucket level override bucket policies. But they only block policies that grant access to Principal: * — a policy granting access to a specific external account bypasses BPA entirely. BPA is not a substitute for correct bucket policy authoring.

What a Secure Bucket Policy Looks Like

Allow only the specific actions needed. Replace s3:* with s3:GetObject for a read-only use case. Require SecureTransport. Add a Condition requiring aws:SourceArn or aws:PrincipalOrgID if the bucket must be accessed cross-account. Never leave Principal: * unconditioned.

Originally published at shieldly.io/blog. Analyze S3 bucket policies at shieldly.io/app/iam.