Cloud Storage Misconfigurations: Hunting Exposed S3 and GCS Buckets

Cloud Storage Misconfigurations: Hunting Exposed S3 and GCS Buckets

A field guide to discovering, safely confirming, and accurately assessing impact on publicly exposed object storage across every major cloud provider.

HackerSavanna Security Team

Security research and platform engineering at HackerSavanna.

5 min read8 views

Exposed cloud storage is one of the oldest bug classes in the modern web, and it still shows up constantly, because the failure mode isn't a code bug at all. It's a configuration default that's easy to get wrong once and never revisit. This is a field guide to finding these misconfigurations methodically across S3, Google Cloud Storage, and Azure Blob Storage.

Why this bug class refuses to die

Object storage buckets default to private on every major provider today, which is genuine progress from a decade ago. But defaults get overridden constantly, for entirely reasonable-sounding reasons in the moment: a developer needs to quickly share a file with a client, a CI pipeline needs to publish build artifacts, a static site needs public read access to serve assets. Each of those is a legitimate use case. The problem is scope: "public read on this one folder of marketing assets" quietly becomes "public read on the whole bucket" far more often than anyone intends, and almost nobody audits bucket policies after the fact.

Discovery: finding the bucket in the first place

Bucket names aren't secret by design, they're just unglamorous strings, and most organizations use predictable naming conventions.

bash150 Bytes
1# Common patterns worth trying against a target
2company-assets
3company-backups
4company-uploads
5company-static
6company-dev
7company-staging
8company-prod

Combine this with permutation tools built for exactly this purpose:

bash122 Bytes
1# S3Scanner checks bucket existence and permission level in one pass
2s3scanner scan --bucket-file company_bucket_names.txt

Passive discovery is often more productive than guessing. Search engines index public bucket URLs that show up in JavaScript bundles, CDN configuration, or leaked CI logs:

plaintext87 Bytes
1site:s3.amazonaws.com "company-name"
2intitle:"index of" "s3.amazonaws.com" company-name

And check the target's own frontend JavaScript for hardcoded bucket references, which is often the fastest path of all:

bash105 Bytes
1curl -s https://target.example.com/static/main.js | grep -oE "[a-z0-9.-]+\.s3[a-z0-9.-]*\.amazonaws\.com"

Confirming exposure without touching data you shouldn't

Once you have a candidate bucket, confirm public access with a read-only, non-destructive request before doing anything else:

bash51 Bytes
1aws s3 ls s3://target-bucket-name --no-sign-request

--no-sign-request is the key flag. It makes the request as an anonymous, unauthenticated caller, which is exactly the perspective that matters for this finding. If the listing succeeds, you've confirmed public read access to the bucket contents without needing any credentials of your own.

For Google Cloud Storage, the equivalent check:

bash33 Bytes
1gsutil ls gs://target-bucket-name

And for a quick, no-tooling-required check on any provider, a plain unauthenticated HTTP request to the bucket's listing endpoint often works:

bash66 Bytes
1curl -s "https://target-bucket-name.s3.amazonaws.com/?list-type=2"

A 200 response with an XML object listing is your confirmation. A 403 AccessDenied at least confirms the bucket exists, which is still worth documenting, since some programs consider bucket enumeration plus a misconfigured CORS policy or a related permissions gap in scope even when a straight listing is blocked.

What actually matters: assessing real impact

Not every exposed bucket is the same severity, and this is where reports frequently under- or over-state the finding. Before writing anything up, establish:

  • Is it listable, readable, or writable? These are three different findings. Public write access, where anyone can upload or overwrite objects, is often the most severe, since it opens the door to serving attacker-controlled content from the company's own trusted domain, a supply chain risk far beyond simple data exposure.
  • What's actually in it? A bucket serving public static assets for a marketing site is a non-issue by design. The same misconfiguration on a bucket containing user-uploaded documents, database backups, or .env files pulled in by an overly broad CI artifact upload step is a critical data exposure.
  • Does it expose credentials that unlock further access? Backup buckets in particular frequently contain configuration files with database connection strings or API keys, turning a storage misconfiguration into a much deeper compromise if you follow the chain (responsibly, and within scope).
bash210 Bytes
1# A sanity check for genuinely sensitive filenames, without downloading bulk data
2aws s3 ls s3://target-bucket-name --no-sign-request --recursive | grep -iE "\.env|backup|\.sql|password|credentials|\.pem|\.key"

Only pull down the minimum needed to confirm sensitivity for your report. Bulk-downloading an entire exposed bucket is rarely necessary to prove impact and can create real legal and ethical problems for you as a researcher.

Writing the report

A strong cloud storage exposure report includes:

  • The exact bucket name and the provider
  • The specific command or request used to confirm public access, so the triager can reproduce it in seconds
  • A description of the type of data present, without needlessly reproducing large volumes of it (file names and a small representative sample are usually sufficient)
  • Whether access is read-only or read-write
  • A clear statement of realistic worst-case impact given what's actually stored there

Fixing it, and keeping it fixed

  • Enable the provider's account-level public access block (aws s3control put-public-access-block for AWS, equivalent settings exist for GCS and Azure) as a backstop against any individual bucket policy mistake.
  • Apply least-privilege bucket policies scoped to specific prefixes rather than whole-bucket wildcards when public access is genuinely needed for part of a bucket.
  • Run continuous configuration auditing (AWS Config rules, Google Security Command Center, or third-party tools) rather than relying on a one-time review, since new buckets get created constantly and drift is the actual root cause here, not any single bad decision.

This bug class rewards persistence and good naming-convention instincts more than deep technical tooling, which is exactly why it remains one of the most consistently productive places to spend early recon time on any new target.

Share: