On April 5, 2023, AWS began rolling out a change it had announced the previous December: S3 Block Public Access and disabled ACLs would become the default for every newly created bucket, in every region, including GovCloud and China. It was a tacit admission of how often teams got this wrong on their own. The change did nothing for buckets that already existed — those still needed manual remediation — and it arrived four years after the breach that made "misconfigured S3 bucket" a household phrase in security circles: Capital One's 2019 incident, which exposed data on roughly 106 million people. That breach is worth studying closely, because its root cause wasn't a public bucket or a missing encryption flag at all — it was an over-permissioned IAM role attached to a web application firewall. Two months after Block Public Access shipped, AWS made a second quiet but consequential change: as of January 5, 2023, every new object uploaded to S3 gets SSE-S3 encryption automatically, at no extra cost. Both defaults are good news, but defaults only protect what's created after the switch flips. This checklist covers the five controls — public access, bucket policy, encryption, logging, and IAM — that actually determine whether your S3 estate is safe, including the ones AWS still leaves entirely in your hands.
Is Block Public Access actually on for your buckets?
Block Public Access became the default for new buckets on April 5, 2023, after AWS announced the change on December 13, 2022 — but "new" is the operative word. Every bucket created before that date, and every bucket where a previous IAM policy, ACL, or bucket policy already granted public access, keeps its prior configuration untouched. The setting has four independent switches (block public ACLs, ignore public ACLs, block public bucket policies, restrict public buckets) that can be set at the account level or per bucket, and AWS recommends enabling all four at the account level as a baseline unless a specific bucket has a documented reason to serve public content, like static website hosting. The practical check is straightforward: pull every bucket's Block Public Access configuration via the S3 API or aws s3api get-public-access-block, and treat any bucket where all four settings aren't true as a finding requiring sign-off, not an oversight to quietly fix.
Does your bucket policy enforce least privilege and encrypted transport?
A bucket policy should deny more than it allows, and the two conditions most often missing are a default-deny on unencrypted transport and a restriction to specific principals rather than "Principal": "*". AWS's own security best-practices guidance recommends attaching a policy statement with "Condition": {"Bool": {"aws:SecureTransport": "false"}} set to Deny, which blocks any request made over plain HTTP rather than TLS — a control that costs nothing and catches misconfigured clients or scripts before they ever move data in the clear. Beyond transport, a least-privilege bucket policy names the specific IAM roles, accounts, or VPC endpoints allowed to read or write, and separates read from write permissions where possible. A wildcard principal combined with a broad action list like s3:* is the single most common pattern audits flag, because it's usually left over from a debugging session and never tightened afterward.
Is default encryption actually covering your objects?
Since January 5, 2023, AWS automatically applies SSE-S3 (AES-256) encryption to every new object uploaded to every S3 bucket, with no configuration required and no performance cost, according to AWS's own documentation on the change. The catch is retroactivity: objects uploaded before that date, or before default encryption was separately enabled on a given bucket, were never encrypted after the fact — S3 does not go back and re-encrypt existing objects when a default changes. You can verify actual coverage three ways: S3 Inventory reports, which list the encryption status of every object in a bucket; Storage Lens, which aggregates encryption posture across an entire organization; and CloudTrail, which logs the encryption headers on every PutObject call. Teams that assume "AWS turned this on for us" without checking pre-2023 objects are the ones who find gaps during an actual audit. For buckets holding regulated data, SSE-KMS with a customer-managed key adds an access-control layer SSE-S3 doesn't provide, since KMS key policies require an additional permission check beyond the bucket policy.
Can you tell who accessed a bucket, and when?
S3 offers two logging mechanisms, and most security programs need both, not one or the other. Server access logging records every request made against a bucket — including denied requests — as flat log files delivered to a target bucket, but delivery is best-effort and can lag by hours. CloudTrail data events capture the same S3 API calls with stronger delivery guarantees and integration into a centralized SIEM, but they cost more at high request volumes since every GetObject and PutObject is billed as a logged event. Neither is enabled by default on a new bucket. The practical minimum for any bucket holding sensitive data is CloudTrail data events turned on and routed to a log archive account separate from the account where the bucket lives, so that an attacker who compromises the bucket's own account can't also delete the evidence of what they did.
What did the Capital One breach actually teach the industry?
The Capital One breach, which exposed data on approximately 106 million people across the US and Canada, is the case study that reframed S3 security as an IAM problem as much as a bucket-configuration problem. According to reporting by Krebs on Security and the subsequent legal filings, a former AWS employee exploited a server-side request forgery (SSRF) vulnerability in a misconfigured web application firewall to query the EC2 instance metadata service and retrieve temporary IAM credentials belonging to that WAF's role. Because the role was scoped far more broadly than the WAF needed, those credentials could list and read from more than 700 S3 buckets, and roughly 30GB of data was exfiltrated. The breach activity began March 22, 2019; Capital One didn't discover it until July 19, 2019, and disclosed publicly on July 29. Every bucket involved could have had Block Public Access enabled, a locked-down bucket policy, and full encryption — none of it would have stopped this attack, because the credentials used were legitimately issued to a role that simply had too much reach. That's the fifth checklist item teams skip: auditing which IAM roles attached to compute (EC2, Lambda, ECS tasks) can touch S3, and whether each one's s3:* permissions are scoped to the specific buckets and actions that role actually needs.
Where does this checklist leave a security team?
Put together, the five controls form a layered checklist rather than a single setting to toggle: account- and bucket-level Block Public Access enabled everywhere except documented exceptions; bucket policies that name specific principals and deny insecure transport; encryption verified through Inventory or Storage Lens rather than assumed from the 2023 default; CloudTrail data events or access logging routed to a separate account; and IAM roles attached to any compute that touches S3 reviewed for scope, not just existence. AWS's 2023 default changes closed real gaps, but they only apply going forward and only to the bucket-level controls — they say nothing about the IAM role a Lambda function assumes to read from that bucket. Capital One is the reminder that the checklist's last item is often the one that actually gets exploited.