Back to scan results
Check 16 of 24

Cloud Storage Exposure

Misconfigured S3 buckets are arguably the single biggest source of mass data leaks of the last decade. We try predictable bucket names derived from your domain, on the three major providers, and report any that respond with a public listing.

What this check probes

From your domain (e.g., example.com) we generate predictable bucket name candidates: example, example-com, example-backup, example-uploads, example-static, example-assets, example-prod, example-dev, example-staging.

For each name we send an unauthenticated GET to:

  • AWS S3 — https://{name}.s3.amazonaws.com/ and the regional variants.
  • Google Cloud Storage — https://storage.googleapis.com/{name}/.
  • Azure Blob Storage — https://{name}.blob.core.windows.net/ and probe common container names like $root, backup, data.

A response containing a ListBucketResult XML document, or a EnumerationResults, or a directory-listing HTML page, indicates the bucket exists and allows public listing. A 403 means the bucket exists but listing is denied (still risky if specific filenames are guessable). A 404 means the bucket doesn't exist or isn't bound to the candidate name.

Why this matters for PCI DSS

Almost every cloud-storage data breach in the news (Accenture, Capital One, Verizon, FedEx, Booz Allen Hamilton, Department of Defense, ...) has had the same root cause: a bucket whose access policy was either explicitly public or accidentally public via a default-allow ACL.

Buckets often hold: user uploads, database backups, application source code, infrastructure-as-code with secrets, log files containing tokens, and historical exports of cardholder data.

PCI DSS 4.0 Requirement 3.5.1 — protect stored account data. Requirement 7.2 — restrict access on a need-to-know basis. Requirement 1.4.4 — system components storing cardholder data must not be directly accessible from untrusted networks. A public bucket containing CHD violates all three.

How to fix it

AWS S3 — turn on Block Public Access at the account level. This setting overrides any per-bucket policy and is the single most effective control:

aws s3control put-public-access-block \
    --account-id 123456789012 \
    --public-access-block-configuration \
    "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"

Then audit each bucket: aws s3api get-bucket-policy --bucket NAME and aws s3api get-bucket-acl --bucket NAME.

For buckets that legitimately serve public assets (a static site, a CDN origin), use a CloudFront distribution with an Origin Access Identity rather than direct public S3 access. The bucket stays private, CloudFront has the only access.

Google Cloud Storage — at the project level, enable "Public access prevention":

gcloud storage buckets update gs://BUCKET --public-access-prevention

Audit IAM with gcloud storage buckets get-iam-policy gs://BUCKET; remove allUsers and allAuthenticatedUsers bindings.

Azure Blob Storage — set the storage account's "Allow Blob anonymous access" to Disabled (Azure Portal → Storage account → Configuration). Then per container, ensure access level is "Private (no anonymous access)".

For private content access, use signed/presigned URLs with short expiry, never public ACLs. AWS, GCS, and Azure all support this pattern in every SDK.

Once a quarter, run an external scan with S3Scanner or cloud_enum against bucket names predictable from your brand.

Fixed it? Re-run the scan to confirm.

Run scan again