threatfound
Cloud Security
Cloud Security · lesson 02

Public buckets & storage exposure

Object storage left readable or writable to the world is a top recurring cloud leak; this lesson explains how it happens, how it's found, and how to lock it down.

9 min read

Object storage services like Amazon S3, Google Cloud Storage (GCS), and Azure Blob Storage hold buckets of files (objects) that are private by default. A storage exposure happens when a bucket or its objects are made reachable by anyone on the internet through a misconfiguration, turning a private data store into a public download. It is one of the most persistent causes of cloud data leaks precisely because a single wrong setting can expose everything inside.

How buckets end up public

Exposure is almost never a bug in the storage service itself. It is a configuration choice that grants access more broadly than intended. The common causes:

  • Object or bucket ACLs set to public-read — a legacy access-control list that grants the AllUsers group read access, often applied per-object during uploads so the bucket looks locked but individual files are wide open.
  • Over-broad bucket policies — a JSON policy with Principal: "*" and a permissive Action (for example s3:GetObject on the whole bucket) that intends to serve one asset but exposes the entire prefix.
  • Misreading `AuthenticatedUsers` — in AWS this group means *any* authenticated AWS account holder on earth, not your organization's users. Granting it access is effectively public to anyone with a free AWS login.
  • Block Public Access disabled — the account- or bucket-level guardrail that overrides risky ACLs and policies is turned off, so the misconfigurations above actually take effect.
  • Static-site or CDN shortcuts — flipping a bucket to public to make it serve a website, then dumping unrelated backups or exports into the same bucket.

Why it matters: read vs write

The impact splits cleanly by which permission leaked. Public read means mass disclosure: customer PII, database backups, internal source code, credentials in config files, and access logs can all be downloaded in bulk by anyone who finds the bucket. Because storage is where teams stash exports and snapshots, a single readable bucket often exposes more than the production database it was copied from.

Public write is worse and less obvious. If anyone can upload or overwrite objects, an attacker can tamper with the files you serve — replacing a JavaScript file loaded by your site (a supply-chain attack on every visitor), hosting malware or phishing pages under your trusted domain, or corrupting backups you rely on for recovery. Write exposure turns your own storage into an attack platform pointed at your users.

How exposure is discovered

Attackers and researchers find open buckets without any privileged access, which is what makes this class of leak so easy to stumble into:

  • Predictable names — buckets named companyname-backups, acme-prod-uploads, or myapp-dev are guessable at scale. Wordlists of common suffixes are brute-forced against the storage endpoint.
  • Leaked references — bucket URLs sitting in a site's HTML, in bundled JavaScript, in mobile app binaries, or exposed via Certificate Transparency (CT) logs when a bucket is fronted by a named certificate.
  • Listing an open bucket — if list permission is public, a single request returns an index of every object, letting anyone enumerate and pull the contents.
# The kind of unauthenticated check that reveals an OPEN bucket.
# Run ONLY against a bucket you own.

# No credentials, still lists contents = public listing enabled
aws s3 ls s3://my-own-test-bucket --no-sign-request

# Anonymous object fetch succeeds = public-read on the object
curl -s -o /dev/null -w "%{http_code}\n" \
  https://my-own-test-bucket.s3.amazonaws.com/backup.sql
careful

Only test buckets you own or are explicitly authorised in writing to assess. A bucket being publicly reachable is not permission to access it — downloading or listing another organization's data is unauthorised access and is illegal in most jurisdictions regardless of how the bucket was configured. If you find someone else's exposed bucket, report it through their security contact; do not download the contents.

Defense: how to prevent it

Lock exposure down in layers so no single mistake is enough to leak data. In priority order:

  • Enable Block Public Access at the account level (and per bucket). This is the master switch: it overrides any public ACL or policy so a stray misconfiguration cannot actually expose data. Turn it on org-wide first.
  • Disable ACLs entirely — set object ownership to bucket-owner-enforced so per-object public-read ACLs simply cannot be applied. This removes the most common accidental exposure path.
  • Write least-privilege bucket policies — never Principal: "*" for private data; scope access to specific IAM roles, prefixes, and actions. If a bucket must serve public assets, isolate those in a dedicated bucket that holds nothing else.
  • Turn on default encryption so objects are encrypted at rest without relying on per-upload settings.
  • Enable access logging and monitoring — server access logs plus alerts (for example on a public-access-block being disabled) so a change to public gets noticed fast.
  • Run periodic external checks — from an unauthenticated position, confirm your own buckets refuse anonymous list and get requests. Automate this so a future change that re-exposes a bucket is caught.
tip

Treat "is it public?" as a monitored state, not a one-time setup task. Wire an alert to the configuration change itself — someone disabling Block Public Access or attaching a wildcard policy — because exposure usually returns through a well-meaning change months after the initial audit, not through the original setup.