Back to scan results
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.