S3 misconfiguration has been a durable problem in cloud security for years. Despite AWS adding Block Public Access controls, default-private bucket settings, and better console warnings, teams keep creating buckets in configurations that expose data they didn't intend to expose. This isn't carelessness. The access model is genuinely complex: bucket policies, ACLs, IAM policies, and Block Public Access settings interact in ways that produce unexpected outcomes even when each setting looks reasonable in isolation.
What follows is a technical walkthrough of five specific patterns we find repeatedly during data discovery scans. The title says five patterns and counts them that way, but this isn't a listicle. These are grounded descriptions of how misconfiguration actually happens, what the configuration looks like when we find it, and what the right remediation path is.
Pattern 1: Block Public Access disabled at the account level, not the bucket level
AWS Block Public Access (BPA) can be applied at two levels: the account level and the individual bucket level. When BPA is enabled at the account level, it overrides bucket-level settings and prevents any public access regardless of bucket policy or ACL. When BPA is disabled at the account level but enabled on individual buckets, those buckets are protected, but any new bucket created without an explicit BPA configuration inherits the account-level setting and is therefore unblocked by default.
The scenario we see: an organization enables BPA on their known production buckets individually, but the account-level setting is off. An engineer creates a bucket for a new data pipeline, doesn't set BPA explicitly, and the bucket is created without public access blocking. If a bucket policy is then added that grants access to a broad principal (or if no policy is added and a legacy ACL grants public-read), the bucket is exposed.
The correct configuration is BPA enabled at the AWS account level as a baseline, enforced via AWS Config rule s3-account-level-public-access-blocks-periodic. Individual buckets that need any form of public access (static website hosting, for example) should be explicitly documented exceptions.
Pattern 2: Bucket policies with overly broad principal wildcards
S3 bucket policies allow you to define who can perform which actions on a bucket or its objects. The Principal field determines the grantee. The most dangerous version is "Principal": "*", which means any AWS principal, including unauthenticated requests if the Condition block is absent or doesn't require authentication.
But the patterns short of full wildcard are more common and harder to catch:
"Principal": {"AWS": "*"}with a condition that checks only for a specific VPC endpoint ID. If that endpoint is shared across accounts or accessible to more services than intended, the scope is wider than assumed.- Cross-account principals specified with account IDs that are no longer active (an acquired company's account, a former vendor's account, or an account that was deleted but whose ID was never cleaned from the policy).
- Wildcard within an ARN pattern, such as
arn:aws:iam::123456789012:role/data-*, intended to cover three specific roles but matching any role whose name starts with "data-" in that account, including newly created ones.
When we scan bucket policies, we flag every non-specific principal: wildcards, cross-account principals, and ARN patterns with wildcards. Then we cross-reference against actual usage logs to determine which of those access paths are real versus theoretical. The policy says it allows a broad principal; whether anyone is actually using that access is a separate question, and the answer changes the remediation priority significantly.
Pattern 3: Object-level ACLs granting public-read after BPA was added
This one surprises teams that thought they were protected. AWS Block Public Access has a specific toggle: BlockPublicAcls prevents NEW ACL grants, but if a bucket had object-level ACLs set to public-read before BPA was enabled, those existing ACL entries remain. The object is still publicly accessible unless the existing ACLs are explicitly revoked.
The sequence: a bucket was created years ago with public-read ACLs on objects, used for hosting some public assets. The use case changed, the bucket now receives a mix of public and internal objects, someone enables BPA going forward, but the existing objects with public-read ACLs are still readable by anyone with the URL. The engineering team believes the bucket is now protected. The legacy objects are not.
Detection requires checking not just bucket-level settings but actual object ACL state on existing objects. For large buckets, you can't do this manually. The remediation is to disable ACLs entirely on the bucket (available since AWS introduced the Bucket Ownership Controls feature in 2022) and rely on bucket policies only, which eliminates this entire class of residual exposure.
Pattern 4: Cross-region replication targets with different access controls
S3 cross-region replication (CRR) copies objects from a source bucket to one or more destination buckets in other regions. It's used for disaster recovery, data residency compliance, and latency optimization. The security gap: the destination bucket has its own access controls, independent of the source. If the destination bucket is less restrictive than the source, replication creates a more-accessible copy of your data.
We see this in a specific pattern: a production bucket in us-east-1 has strict access controls, VPC endpoint restrictions, and logging enabled. The replication destination in eu-west-1 was set up quickly as a DR copy, has a more permissive bucket policy (perhaps because the engineer setting it up was working from a template used for non-sensitive buckets), and doesn't have VPC restrictions. The data is identical. The controls are not.
When building your data inventory, replication relationships must be tracked. If bucket A contains PII and replicates to bucket B, bucket B must be classified as containing PII and audited with the same control requirements. This seems obvious stated plainly, but automated replication makes it easy to create copies without them appearing in your mental model of "where sensitive data lives."
Pattern 5: Presigned URL generation from overly privileged roles
S3 presigned URLs grant temporary, time-limited access to an object without requiring the caller to have AWS credentials. They're generated by an IAM principal that has S3 access, and the generated URL inherits the permissions of that principal. When the generating role has broad S3 access, presigned URLs can be generated for objects across many buckets.
The exposure pattern: an application service uses a role with s3:GetObject on a wildcard resource (arn:aws:s3:::*) because it needs to access objects in multiple buckets for its core function. The same service also has an API endpoint that generates presigned URLs based on user-supplied object keys. If input validation on that key is insufficient, an attacker can request a presigned URL for an object in any bucket the role can access, not just the buckets the application was designed to serve.
The role-level fix is least-privilege: scope the role's S3 access to the specific bucket ARNs it needs. The application-level fix is validating that requested object keys resolve to allowed buckets before generating the presigned URL. Both are needed. The role fix is the durable one, because application-level validation can have edge cases; a role that physically cannot read from bucket X cannot generate a valid presigned URL for objects in bucket X regardless of what the application does.
What systematic detection looks like
Running these checks manually against a few buckets is straightforward. Running them continuously across all buckets in all accounts, including buckets created last week, is the operational challenge.
The detection approach we take at PostQKey combines several signals: bucket policy analysis (parsed and flagged for overly broad principals), ACL state on objects (sampled and flagged for public-read entries on non-public-use buckets), BPA configuration at both account and bucket level, cross-account access relationships, and replication topology. Each of those checks is a data point. The finding is the combination: this bucket contains data classified as PII, and one of these access vectors is open.
We're not saying a misconfiguration without sensitive data in the bucket is not worth fixing. It is. But prioritization requires knowing what's in the bucket. Two buckets with identical misconfigurations but different content classifications should be remediated in a different order. That's the data-awareness layer that DSPM adds on top of what a CSPM tool gives you.
The patterns above don't exhaust the space of S3 exposure. Lifecycle policies that move objects to public-compatible tiers, access point configurations that bypass bucket policies, and S3 Object Lambda access points with insufficiently scoped permissions are all worth examining. The five above are the ones we find most reliably across different organizations and different ages of AWS account, which is why they are the ones to audit first.