S3 bucket ACL permits listing by all users

Remove public S3 bucket ACLs and check permissions for object listings and contents separately.

Description

An effective AccessControl: PublicRead bucket ACL can let anyone, including anonymous callers, list objects in the bucket. Bucket-level READ is different from permission to read object contents; review each object’s read access separately.

New buckets disable ACLs and block public access by default. Actual exposure depends on Object Ownership, account and bucket Block Public Access settings, and the complete policies.

Potential impact

  • Object names and paths can reveal internal structure or information about stored data.
  • If object reads are separately allowed, external callers may also retrieve the contents.

Remediation

  • Configure policies for required existing access before disabling ACLs with BucketOwnerEnforced.
  • Keep Block Public Access enabled where public access is unnecessary. Review bucket policies and existing object ACLs together.
  • Verify that intended access continues to work and unwanted anonymous listings and reads are blocked.

Examples

These are alternative configurations for the same bucket. Supply a globally unique BucketName. The first shows the prerequisites for a public ACL and is not recommended. Account or organization protections may still block it; do not remove them to run the example.

Before

yaml
Parameters:
  BucketName:
    Type: String
Resources:
  JenkinsArtifacts01:
    Type: AWS::S3::Bucket
    Properties:
      AccessControl: PublicRead
      BucketName: !Ref BucketName
      OwnershipControls:
        Rules:
          - ObjectOwnership: ObjectWriter
      PublicAccessBlockConfiguration:
        BlockPublicAcls: false
        IgnorePublicAcls: false
        BlockPublicPolicy: true
        RestrictPublicBuckets: true
      Tags:
        - Key: CostCenter
          Value: ITEngineering

ACLs and public ACL grants are enabled at the bucket level. Anonymous listing may be allowed if no other controls block it.

After

yaml
Parameters:
  BucketName:
    Type: String
Resources:
  JenkinsArtifacts01:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketName
      OwnershipControls:
        Rules:
          - ObjectOwnership: BucketOwnerEnforced
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        IgnorePublicAcls: true
        BlockPublicPolicy: true
        RestrictPublicBuckets: true
      VersioningConfiguration:
        Status: Enabled
      Tags:
        - Key: CostCenter
          Value: ITEngineering
        - Key: Type
          Value: CICD

ACLs are disabled and all four Block Public Access settings are enabled. Migrate required access to policies before applying it. Versioning is a separate recovery feature; it does not block public access.

References