If your AWS account is new since April 2023, you probably never had to turn on S3 Block Public Access (BPA) because it’s set up by default. And if you inherited an older account, chances are someone, at some point, flipped all four BPA switches at the account level and called it done.

The problem here is that BPA solves one specific problem, which is the public ACLs and public bucket policies, and that’s not the only road to an exposed S3 bucket.


Why this matters

S3 data leaks didn’t stop happening in 2023. Most of the ones still showing up today have nothing to do with a public ACL or a bucket policy with (Principal: “*) come from overly permissive IAM roles, presigned URLs handed out without control, or KMS key policies nobody audits because “the bucket is already protected.” BPA is necessary. It is not sufficient.

Here are four settings for this, without the ambiguity:

But first of all, BPA isn’t a single switch; it’s four independent settings, applicable at the access point, bucket, account, or organization level:

  • BlockPublicAcls: actively rejects any attempt to write a public ACL. Acts at write time.
  • IgnorePublicAcls: lets the write happen, but S3 ignores that public ACL when evaluating access. Acts at read/evaluation time.
  • BlockPublicPolicy: rejects applying a bucket policy (or access point policy) that S3 classifies as public.
  • RestrictPublicBuckets: If a bucket ends up with a public policy anyway, this setting restricts access to only AWS service principals and users within the owning account, blocking cross-account access too.

The rule that decides everything: the most restrictive combination wins

When organization, account, bucket, and access point have different settings, S3 doesn’t apply “the most specific one”; it applies the most restrictive combination across every level that applies. An individual bucket can’t lower protection below what the account already enforces.

This also closes a real bypass: if BlockPublicPolicy only lives at the bucket level, anyone with permission to modify the bucket policy (s3:PutBucketPolicy) could, in theory, first disable the bucket’s BPA setting and then apply a public policy. If BlockPublicPolicy is enforced at the account level instead, that same bypass requires the far more sensitive s3:PutAccountPublicAccessBlock permission that is normally reserved for account administrators.


The three vectors BPA doesn’t cover

BPA controls the resource side (ACLs and resource-based policies). It does not control the identity side:

  1. Identity-based IAM policies: a role with broad s3:GetObject works exactly the same with BPA fully enabled.
  2. KMS resource policies: a permissive key policy can expose an encrypted object without BPA ever entering the picture.
  3. Presigned URLs: a URL signed with SigV4 is evaluated as an authenticated request from the IAM principal who signed it, not as public access via an ACL or bucket policy. BPA never enters that evaluation path, no matter how many of its four settings are turned on.

What to actually do about it

  • Audit IAM, not just S3. Look for roles and users with s3:* or s3:GetObject on Resource: “*”.
  • Control who can sign presigned URLs.
  • Review the KMS key policies behind any keys used to encrypt sensitive S3 objects.
  • Use IAM Access Analyzer for S3 as an additional visibility layer.

BPA answers the question, “Can anyone on the internet read this bucket through its ACL or policy?” It doesn’t answer, “Can someone with the right credentials or the right URL read this bucket anyway?” That second question is the one that actually matters for a real security audit.

My advice is turn BPA ON! Just don’t mistake it for the end of the audit.


Hope this helps. See you next time.

From the digital trenches, George. 👋