Skip to main content
cd ../config-traps
risk/register/s3-putbucketpolicy-ignores-block-public-access-state.html
AWS S3 Access Controlhigh severityAWS S3

S3 PutBucketPolicy Ignores Block Public Access State

Severity
high
Reviewed
20 Jul 2026
Remediation
~20 minutes
Overview

A wildcard bucket policy can be written and saved successfully in S3 even while every Block Public Access flag is enabled, because the API validates syntax, not exposure. The bucket sits dormant until someone flips the account-level BPA setting, and objects go public with no new policy event in CloudTrail to catch.

Operational summary

At a glance

Symptom
Account-level or bucket-level Block Public Access is disabled or was never enabled, instantly activating an already-saved wildcard policy.
Likely cause
PutBucketPolicy accepts Principal: "*" successfully regardless of current Block Public Access state, since enforcement happens only at data-plane read/write time.
Impact
Every object under the affected bucket becomes publicly accessible with no corresponding PutBucketPolicy event for alerting tools to catch.
Verification signal
Re-run the detection test and a controlled negative-path test.
Safe correction
Lock Block Public Access at the account level via s3control put-public-access-block, deny changes through an SCP, and monitor exposure continuously with IAM Access Analyzer for S3.
Rollback or recovery
Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.

The Trap

PutBucketPolicy accepts a resource policy with "Principal": "*" and no scoping conditions regardless of the bucket’s or account’s Block Public Access configuration. S3 only enforces BlockPublicPolicy, IgnorePublicAcls, BlockPublicAcls and RestrictPublicBuckets at data-plane request time, on GetObject, ListBucket and similar calls. The write path is entirely separate from the enforcement path, so a dangerous policy can sit committed and inert for months.

The Default State

Buckets created through the S3 console since 2023 get all four BPA flags set to true automatically. Buckets provisioned through CloudFormation, Terraform or the CLI without an explicit aws_s3_bucket_public_access_block resource, or an equivalent PutPublicAccessBlock call, inherit only whatever the account-level setting provides. Many accounts migrated before the account-level default existed, or had it disabled during a one-off migration and never re-enabled it. Engineers writing the wildcard policy see the PutBucketPolicy call succeed and assume the platform would have rejected an unsafe configuration if one existed.

The Blast Radius

Detection tooling built around CloudTrail alerts on PutBucketPolicy events misses the actual exposure entirely, because the triggering action is a later PutAccountPublicAccessBlock or per-bucket BPA change, not a policy write. The moment account-level BPA is disabled, every wildcard policy already resting in the account activates simultaneously across every affected bucket, with no corresponding policy-change event that day. Static analysis run at deploy time reports the bucket as compliant, since BPA was enabled during the scan, and nobody re-scans after unrelated account-level toggles.

The Lead Mechanic Fix

Treat account-level BPA as a locked control-plane setting rather than a per-project toggle. Apply it explicitly with aws s3control put-public-access-block --account-id ACCOUNT_ID --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true, then deny s3:PutAccountPublicAccessBlock and s3:PutBucketPublicAccessBlock in a Service Control Policy scoped to everyone except a named break-glass role. Because SCPs cannot inspect the content of a resource policy document, pair this with continuous evaluation from IAM Access Analyzer for S3, which flags external access based on actual policy effect at any time, not just at write time, closing the gap that PutBucketPolicy leaves open.

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

aws s3control put-public-access-block --account-id ACCOUNT_ID --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
s3:PutAccountPublicAccessBlock
s3:PutBucketPublicAccessBlock
04

Verify, roll back or escalate

Verify

Re-run the detection test and a controlled negative-path test. Confirm the unsafe behaviour is blocked while approved traffic still succeeds.

Rollback

Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.

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