5 S3 Security Misconfigurations That Turn Private Buckets Into Public Incidents
Amazon S3 closed its most famous security trap in April 2023. New buckets now get Block Public Access enabled and ACLs disabled by default. Good. Necessary. Also not retroactive. That means the S3 problems worth worrying about now are less likely to be a brand-new bucket somebody made public at the end of the day Friday. They’re more likely to be old permissions, stale sharing links, missing logs, and a compatibility feature nobody remembers enabling.The risk moved from “someone clicked the wrong box” to “nobody has checked this in three years.” To help avoid a security nightmare, here are five S3 security misconfigurations worth checking before your next audit, incident, or unpleasantly specific Slack message.
1. Legacy buckets that missed the 2023 defaults
AWS automatically enabled Block Public Access and disabled ACLs for new buckets in April 2023. Existing buckets stayed as they were, with no retroactive cleanup or magical closure of the bucket you created during a bygone era. Start with account-level Block Public Access. Skip the scavenger hunt through individual buckets. S3 combines account-, bucket-, and access-point-level controls and applies the most restrictive effective setting.
aws s3control get-public-access-block \
–account-id 111122223333
If the account does not intentionally host public content, set all four protections:
aws s3control put-public-access-block \
--account-id 111122223333 \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,\
BlockPublicPolicy=true,RestrictPublicBuckets=true
Don’t blindly flip the switch. Check for legitimate public workloads first: static site assets, public downloads, data distribution, or CloudFront origins with unusual access patterns. “We broke production to improve security” is not a great way to start the week.
2. IAM permissions that Block Public Access cannot fix
Block Public Access is excellent at stopping public access through ACLs, bucket policies, and access-point policies. It does not repair overly broad identity-based IAM policies. A role with broad S3 permissions can still do broad S3 things, even while every bucket appears private in the console. That’s how an environment can show zero public buckets and still have far too many principals capable of reading or deleting sensitive data. Look for roles with permissions like:
"Action": "s3:*",
"Resource": "*"
Then ask who is actually using this role now… The usual suspects are old CI roles, “temporary” developer permissions that achieved tenure, and third-party cross-account access left behind after a contract ended. Use IAM Access Analyzer to review external access, inspect cross-account trust relationships, and search identity policies for unrestricted S3 actions.
3. Presigned URLs with a longer half-life than the request
A presigned URL is a bearer token. Whoever has it can use the access it grants until it expires, without needing AWS credentials of their own. AWS explicitly recommends protecting them accordingly.That matters because a link has a habit of traveling: ticket, chat, forwarded email, copied document, browser history.
URLs created with IAM user credentials can last up to seven days when generated through the CLI or SDK. URLs created with temporary credentials cannot outlive the underlying session, which makes role-based generation the safer default. For sensitive objects:
- Generate links from assumed roles rather than long-lived IAM user keys.
- Set expiry windows based on the actual task, not vague optimism.
- Use the s3:signatureAge condition key to reject stale requests.
- Where appropriate, restrict requests by aws:SourceIp, aws:SourceVpc, or aws:SourceVpce.
The goal is simple: a vendor download link should not remain useful after the vendor is long gone.
4. CloudTrail data events that are still off
CloudTrail management events will tell you who changed a bucket policy. They will not automatically tell you who read, wrote, or deleted individual S3 objects. Those object-level records are CloudTrail data events, and they are off by default because they can be high-volume and incur additional charges.
During an incident, that distinction becomes painfully obvious. You may know when access changed, but not which objects were retrieved while it was open.
Enable S3 data events for buckets and prefixes that contain regulated, customer, financial, or otherwise sensitive data. Use advanced event selectors to focus on the events you need (GetObject, PutObject, and DeleteObject), rather than collecting every event in an account and rediscovering the meaning of “high-volume.”
Include both read & write events where the incident-response requirement justifies it. A write-only trail tells you who changed an object. A read trail helps answer whether somebody took it.
5. SSE-C configuration nobody meant to keep
SSE-C lets the caller provide the encryption key with each request. S3 does not retain the supplied key itself, which creates a very different operational model from SSE-S3 or SSE-KMS. AWS changed the default in April 2026: SSE-C is now disabled for new general-purpose buckets, and it was disabled for existing buckets in accounts with no SSE-C-encrypted objects. Accounts with existing SSE-C usage were not changed automatically. That makes the check straightforward:
- If your account never used SSE-C, verify that the new protection is active.
- If your account has used SSE-C, assume legacy behavior may remain until you explicitly review and change it.
- If an application truly requires SSE-C, document the dependency and narrowly control who can enable or use it.
- When SSE-C is blocked for a bucket, S3 rejects relevant write, copy, post, multipart-upload, and replication requests that specify SSE-C with 403 AccessDenied.
Also make sure the recovery controls are real. Versioning and Object Lock are not substitutes for least privilege, but they are valuable damage containment when a compromised credential changes or overwrites data.
Start with your oldest buckets
The highest-risk bucket is often a bucket that predates current defaults, outlived the team that created it, and contains objects nobody can quickly inventory. Start with your oldest bucket. Check effective public-access settings, bucket and IAM policies, presigned-URL workflows, CloudTrail data-event coverage, encryption controls, versioning, and Object Lock. Then repeat.
If finding relevant objects across a large S3 estate is the hard part, CloudSee Drive gives teams a browser-based way to search existing S3 buckets by filename, metadata, and tags while respecting existing IAM permissions. That’s useful before an audit, and much more useful before the question becomes, “What exactly was in that bucket?”

Leave A Comment