Skip to main content
cd ../config-traps
risk/register/aws-s3-access-control-setting-fails-quietly.html
AWS S3 Access Controlhigh severity

Private S3 ACL Still Leaves Objects Publicly Readable

Severity
high
Reviewed
4 Aug 2026
Remediation
~20 minutes
Overview

A private S3 ACL does not mean a private bucket. A leftover bucket-policy statement and partially configured Block Public Access settings can leave objects publicly readable until both layers are checked together.

Operational summary

At a glance

Symptom
An Amazon S3 bucket that a team believes is private continues to allow anonymous read access, discovered through access-log anomalies or an external scan…
Likely cause
The root cause is typically a bucket policy statement added earlier for a legitimate purpose, such as a static website or a partner integration…
Impact
Unreviewed public access through a bucket policy can expose stored objects to anonymous read or write requests, independent of what the ACL or the console summary badge implies.Because…
Verification signal
Confirm the bucket reports as non-public through S3's own policy status check rather than relying on the console badge alone.aws s3api get-bucket-policy-status --bucket EXAMPLE-BUCKET-NAMEThe IsPublic field must return…
Safe correction
Apply Block Public Access explicitly across all four settings rather than relying on ACL changes alone, then remove or narrow the offending bucket policy statement.aws s3api get-public-access-block --bucket…
Rollback or recovery
Keep the pre-change output of get-public-access-block and the original bucket policy document saved before applying any correction, so the exact prior state can be restored.If restricting public access…

Symptom

An Amazon S3 bucket that a team believes is private continues to allow anonymous read access, discovered through access-log anomalies or an external scan rather than through the console itself.

The bucket’s ACL and the console’s ‘Block public access’ indicator both appear correct for a private bucket, yet objects remain retrievable by an unauthenticated request from outside the account.

False Assumption

The team assumes that a private ACL, or a ‘private’ status badge in the console, is sufficient evidence that the bucket denies public access.

In Amazon S3, ACLs, bucket policies, IAM policies and Block Public Access settings are independent, separately evaluated layers. By default S3 grants access if any applicable policy allows it and no explicit deny applies, so a private ACL does not remove a permissive statement sitting in the bucket policy.

Root Cause

The root cause is typically a bucket policy statement added earlier for a legitimate purpose, such as a static website or a partner integration, that still contains a broad Principal value, combined with Block Public Access settings that were never enabled for the policy dimension.

Block Public Access is exposed as four separate controls: BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy and RestrictPublicBuckets. The console’s single toggle sets all four together, but infrastructure-as-code templates require each value set explicitly. A template that only addresses the ACL-related pair leaves any public bucket policy statement fully enforced.

Impact

Unreviewed public access through a bucket policy can expose stored objects to anonymous read or write requests, independent of what the ACL or the console summary badge implies.

Because the exposure is invisible from the ACL view alone, it commonly survives change reviews that check only ACL settings, and can remain undetected until an external scan or a dedicated audit inspects the bucket policy and all four Block Public Access flags together.

Diagnosis

Confirm the actual exposure using read-only checks before changing anything, and use an isolated or non-production account first if this workflow is unfamiliar.

  • Retrieve the bucket policy document and inspect every statement’s Effect, Principal and Resource fields.
  • Retrieve the ACL grants to confirm they are, in fact, private.
  • Retrieve the Block Public Access configuration and record all four boolean values.
  • Call the policy status check to obtain S3’s own computed public or private verdict.
Block Public Access settings and what each one governs
SettingGoverns
BlockPublicAclsRejects new public ACL grants on PUT requests
IgnorePublicAclsIgnores existing public ACL grants when evaluating access
BlockPublicPolicyRejects new bucket policy statements that grant public access
RestrictPublicBucketsRestricts access for buckets with a public policy, including some cross-account cases

If the policy status check reports the bucket as public while the ACL is private, the bucket policy is the active source of exposure, and the correction below targets that layer specifically.

Correction

Apply Block Public Access explicitly across all four settings rather than relying on ACL changes alone, then remove or narrow the offending bucket policy statement.

aws s3api get-public-access-block --bucket EXAMPLE-BUCKET-NAME
aws s3api put-public-access-block 
  --bucket EXAMPLE-BUCKET-NAME 
  --public-access-block-configuration 
  BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

Before applying RestrictPublicBuckets, confirm with the owners of any legitimate cross-account or static-hosting integration that depends on the current policy, since this setting can remove access those integrations rely on. Where access is legitimate, replace the wildcard principal with the exact account ID or role ARN instead of leaving the policy broad and disabling Block Public Access to compensate.

Validation

Confirm the bucket reports as non-public through S3’s own policy status check rather than relying on the console badge alone.

aws s3api get-bucket-policy-status --bucket EXAMPLE-BUCKET-NAME

The IsPublic field must return false. Follow this with an unauthenticated request to a known object URL from outside the account network to confirm the response is 403 Forbidden rather than 200 OK. Re-run get-public-access-block afterwards to confirm all four settings persisted, since a later infrastructure-as-code apply from an out-of-date template can silently revert them.

Rollback

Keep the pre-change output of get-public-access-block and the original bucket policy document saved before applying any correction, so the exact prior state can be restored.

If restricting public access breaks a dependent integration, restore the previous Block Public Access values from the saved output and open a scoped change to correct the bucket policy principal instead of leaving the bucket open. Treat any rollback of Block Public Access as temporary and pair it with a follow-up ticket to narrow the policy.

Prevention

Set all four Block Public Access values explicitly in every infrastructure-as-code template that creates or updates an S3 bucket, rather than relying on provider defaults or a single ACL-related flag.

Add the bucket policy status check and all four Block Public Access flags to routine access reviews and drift detection, not only the ACL. Review bucket policies whenever an integration that required a broad principal is decommissioned, since orphaned wildcard statements are a common way this trap persists long after its original purpose has ended.

03

Apply the safer control

Before you change production

Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.

Fix commands and configuration

Principal
BlockPublicAcls
IgnorePublicAcls
04

Verify, roll back or escalate

Verify

Confirm the bucket reports as non-public through S3's own policy status check rather than relying on the console badge alone.aws s3api get-bucket-policy-status --bucket EXAMPLE-BUCKET-NAMEThe IsPublic field must return false.

Rollback

Keep the pre-change output of get-public-access-block and the original bucket policy document saved before applying any correction, so the exact prior state can be restored.If restricting public access breaks a dependent integration, restore the previous Block Public Access values from…

Escalate

Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.

After remediation

Further reading stays below the corrective workflow and is selected by platform, category and shared technical keywords.

Discover more

Connected KBY resources