How to Find and Fix Public S3 Buckets Before They Leak Data

A public S3 bucket is behind a huge share of the cloud data leaks you read about. Someone flips a bucket public for a demo, a quick file share, or a static site, and forgets to lock it back down. Months later, customer data is indexed by a search engine and the company is in the news.

The fix is simple. Finding every exposed bucket (across regions, accounts, and the different ways S3 can be made public) is the hard part. Here’s how to do it properly.

The four ways an S3 bucket becomes public

S3 has more than one knob, which is exactly why exposures slip through. A bucket can be public via:

  1. Bucket ACLs: legacy access control lists granting AllUsers or AuthenticatedUsers.
  2. Bucket policies: a policy statement with "Principal": "*" and no condition restricting it.
  3. Object ACLs: individual objects made public even when the bucket isn’t.
  4. Block Public Access disabled: the master switch that, when off, lets the above take effect.

Checking only one of these gives a false sense of safety. A bucket can pass an ACL check and still be wide open through its policy.

Step 1: Turn on Block Public Access account-wide

The single most effective control is S3 Block Public Access at the account level. It overrides bucket and object settings and blocks new public grants.

In the S3 console, go to the account-level settings and enable all four Block Public Access options. Do this first; it stops the bleeding while you audit individual buckets.

The exception: if you genuinely serve a public static site from S3, you’ll configure that specific bucket (ideally behind CloudFront with Origin Access Control) rather than leaving account-wide blocking off.

Step 2: Audit every existing bucket

Block Public Access doesn’t retroactively fix everything in every config, so audit what you have:

aws s3api list-buckets --query "Buckets[].Name"
aws s3api get-public-access-block --bucket my-bucket
aws s3api get-bucket-acl --bucket my-bucket
aws s3api get-bucket-policy --bucket my-bucket

For each bucket, confirm:

  • Block Public Access is on (all four settings).
  • No ACL grants to AllUsers / AuthenticatedUsers.
  • No bucket policy with a wildcard principal and no restricting condition.

This gets tedious fast across dozens of buckets and multiple regions, which is why exposures persist; nobody enjoys doing it by hand every week.

Step 3: Use IAM Access Analyzer

AWS IAM Access Analyzer continuously analyzes resource policies and flags buckets accessible from outside your account or organization. Enable it per region and review its findings. It’s a good backstop, though it focuses on policy-based access and you still want the full picture across ACLs and Block Public Access settings.

Step 4: Fix without breaking your apps

Before you slam a bucket shut, confirm nothing legitimate depends on public access:

  • Check access logs or CloudTrail data events for external read patterns.
  • For a “public” asset bucket (images, downloads), front it with CloudFront + Origin Access Control so the bucket itself stays private.
  • Remove public ACLs and tighten policies to specific principals or VPC endpoints.

Then re-verify. A bucket should read as not public in the console after your changes.

Step 5: Prevent regression

One cleanup isn’t enough; the next engineer can re-expose a bucket tomorrow. Lock it in:

  • Account-level Block Public Access as the default posture.
  • Service Control Policies (in AWS Organizations) to prevent disabling Block Public Access.
  • Continuous scanning so a newly-public bucket is caught in hours, not after an incident.

Beyond S3: the same risk on every cloud

This isn’t an AWS-only problem. GCP Cloud Storage buckets can grant allUsers, and Azure storage accounts can enable anonymous blob access. If you run multi-cloud, you need the same audit on each provider, and the same continuous check.

Finding public buckets automatically

Walking ACLs, policies, object grants, and Block Public Access settings across every bucket, region, and cloud is exactly the kind of repetitive audit that gets skipped.

Graymole does it for you in one read-only pass. It connects with a read-only role (no agents, no write access) and flags public storage on AWS, GCP, and Azure along with hundreds of other misconfigurations, tracing each finding back to the raw cloud API response so you can verify and fix it with confidence. Run it on a schedule and a newly-exposed bucket shows up before it becomes a headline. The first scan is free.

Related reading