Back to Checks
aws

S3 bucket is not publicly listable by Everyone or any authenticated AWS user

s3_bucket_public_list_acl
Service: s3Severity: critical
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:AwsS3Bucket

Amazon S3 buckets are evaluated for public listing via ACLs. Grants of READ, READ_ACP, or FULL_CONTROL to the AllUsers or AuthenticatedUsers groups are identified. Effective Block Public Access at account or bucket level (notably IgnorePublicAcls and RestrictPublicBuckets) is considered in the evaluation.

Risk

Public listability reveals object names, counts, and structure, enabling reconnaissance and targeted scraping. READ_ACP exposes permission details for further abuse. With FULL_CONTROL, attackers could alter ACLs and disrupt access, undermining confidentiality and risking integrity and availability.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks s3_bucket_public_list_acl

Recommendation

Enable account-level S3 Block Public Access (BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy, RestrictPublicBuckets).

  • Remove ACL grants to AllUsers/AuthenticatedUsers; apply least privilege with IAM/bucket policies.
  • Favor private patterns (VPC endpoints, CloudFront OAC, presigned URLs) and disable ACLs via Object Ownership.

Remediation

CLI

aws s3api put-public-access-block --bucket <bucket_name> --public-access-block-configuration IgnorePublicAcls=true,RestrictPublicBuckets=true

Terraform

# Block public listing by enabling bucket-level Public Access Block
resource "aws_s3_bucket_public_access_block" "<example_resource_name>" {
  bucket                 = "<example_resource_id>"
  ignore_public_acls     = true  # Critical: ignore any public ACLs
  restrict_public_buckets = true # Critical: restrict buckets with public policies
}

NativeIaC

# CloudFormation: Block public listing via bucket-level Public Access Block
Resources:
  ExamplePublicAccessBlock:
    Type: AWS::S3::BucketPublicAccessBlock
    Properties:
      Bucket: "<example_resource_name>"
      PublicAccessBlockConfiguration:
        IgnorePublicAcls: true        # Critical: ignore any public ACLs so they don't grant list access
        RestrictPublicBuckets: true   # Critical: restrict buckets with public policies to trusted principals

Other

1In the AWS Console, go to S3 and open the bucket
2Select the Permissions tab
3Click Edit under Block public access (bucket settings)
4Enable:
5- Ignore public ACLs (bucket and objects)
6- Restrict public buckets
7Click Save

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.s3.s3_client import s3_client
from prowler.providers.aws.services.s3.s3control_client import s3control_client


class s3_bucket_public_list_acl(Check):
    def execute(self):
        findings = []
        # 1. Check if public buckets are restricted at account level
        if (
            s3control_client.account_public_access_block
            and s3control_client.account_public_access_block.ignore_public_acls
            and s3control_client.account_public_access_block.restrict_public_buckets
        ):
            report = Check_Report_AWS(
                metadata=self.metadata(),
                resource=s3control_client.account_public_access_block,
            )
            report.status = "PASS"
            report.status_extended = "All S3 public access blocked at account level."
            report.region = s3control_client.region
            report.resource_id = s3_client.audited_account
            report.resource_arn = s3_client.account_arn_template
            findings.append(report)
        else:
            # 2. If public access is not blocked at account level, check it at each bucket level
            for bucket in s3_client.buckets.values():
                if bucket.public_access_block:
                    report = Check_Report_AWS(metadata=self.metadata(), resource=bucket)
                    report.status = "PASS"
                    report.status_extended = (
                        f"S3 Bucket {bucket.name} is not publicly listable."
                    )
                    if not (
                        bucket.public_access_block.ignore_public_acls
                        and bucket.public_access_block.restrict_public_buckets
                    ):
                        # 3. If bucket has no public block, check bucket ACL
                        for grantee in bucket.acl_grantees:
                            if grantee.type in "Group":
                                if (
                                    "AllUsers" in grantee.URI
                                    or "AuthenticatedUsers" in grantee.URI
                                ) and (
                                    grantee.permission == "FULL_CONTROL"
                                    or grantee.permission == "READ"
                                    or grantee.permission == "READ_ACP"
                                ):
                                    report.status = "FAIL"
                                    report.status_extended = f"S3 Bucket {bucket.name} is listable by anyone due to the bucket ACL: {grantee.URI.split('/')[-1]} having the {grantee.permission} permission."

                    findings.append(report)
        return findings