Skip to main content
emnode
Compliance Critical severity

AWS Security Hub · S3

S3.3: Buckets can be written to by anyone on the internet

Written and reviewed by Emnode · Last reviewed

What does AWS Security Hub S3.3 check?

S3.3 fails any bucket that allows public write access: anyone on the internet can upload, overwrite, or delete objects.

Why does S3.3 matter?

A publicly writable bucket is even more dangerous than a readable one: attackers can plant malware, deface hosted content, rack up storage costs, or overwrite legitimate data. If the bucket serves a website or feeds a pipeline, public write is a direct path to supply-chain compromise.

How do I fix S3.3?

  1. Enable Block Public Access on the bucket to stop public writes immediately.
  2. Strip any policy statements or ACL grants that give write/PutObject/DeleteObject to Principal "*".
  3. Grant uploads only to specific authenticated roles, ideally scoped to a prefix and protected with conditions.

Remediation script · bash

# Close the highest-impact public exposure first: databases.
for db in $(aws rds describe-db-instances \
    --query 'DBInstances[?PubliclyAccessible==`true`].DBInstanceIdentifier' --output text); do
  aws rds modify-db-instance --db-instance-identifier "$db" \
    --no-publicly-accessible --apply-immediately
  echo "$db: public access removed"
done

# Ratchet S3 shut at the account level so no bucket can be made public again.
aws s3control put-public-access-block --account-id 123456789012 \
  --public-access-block-configuration \
    'BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true'

Full walkthrough (console steps, edge cases and verification) in the lesson Block public access to AWS resources.

Is S3.3 a false positive?

A genuinely public drop box (an upload endpoint anyone on the internet is meant to write to) is the rare case AWS itself flags, and S3.3 will fail it correctly. More often the false alarm is the reverse: the control evaluates the block public access settings, bucket policy, and ACL, but it does not evaluate bucket-policy conditions that use wildcard characters or policy variables, so a statement you've scoped down with a variable or wildcard condition (an aws:SourceVpce, aws:username, or similar guard) is read as if the condition weren't there and reported as public write. If the bucket really is meant to be reachable by everyone, document the business case and suppress the finding rather than flipping on Block Public Access; if it only looks public because of a wildcard or variable condition, rewrite that statement to use fixed values so the control can evaluate it and pass.

Part of the learning path Trim your network spend
  • S3.1 Account-level S3 public access is not fully blocked
  • S3.2 Public S3 buckets expose data to anyone on the internet
  • S3.5 S3 is accepting unencrypted HTTP requests
  • S3.6 Bucket policy grants broad access to other AWS accounts
  • S3.8 Buckets can still be made public; Block Public Access is off
  • S3.9 No S3 access logs, so reads and writes go unaudited
  • S3.10 Versioned buckets should have lifecycle configurations
  • S3.11 Buckets should have event notifications enabled
  • S3.12 ACLs should not be used to manage bucket access
  • S3.13 Buckets have no lifecycle rules and grow forever
  • S3.15 Buckets should have Object Lock enabled
  • S3.17 Buckets should be encrypted at rest with KMS keys