Back to Checks
aws

S3 bucket is not publicly accessible to Everyone or Authenticated Users

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

Amazon S3 buckets are evaluated for public access via ACLs and bucket policies. The check identifies account or bucket PublicAccessBlock protections (IgnorePublicAcls, RestrictPublicBuckets) and flags buckets granting group access to AllUsers or AuthenticatedUsers, or with a public bucket policy.

Risk

Publicly accessible buckets jeopardize confidentiality through unauthenticated reads, integrity through write or ACL changes, and availability via object deletion or overwrite. Attackers can mass-exfiltrate data, host malware, or pivot after discovering secrets stored in objects.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks s3_bucket_public_access

Recommendation

Enforce defense in depth: enable S3 Block Public Access at org/account and bucket levels (BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy, RestrictPublicBuckets). Apply least privilege with explicit principals; avoid ACLs via Object Ownership. Use private access patterns (e.g., CloudFront OAC or presigned URLs) and monitor with analyzers.

Remediation

CLI

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

Terraform

# Enable minimal S3 Block Public Access on the bucket
resource "aws_s3_bucket_public_access_block" "example" {
  bucket = "<example_resource_name>"

  ignore_public_acls     = true  # Critical: ignores public ACLs
  restrict_public_buckets = true # Critical: restricts buckets with public policies
}

NativeIaC

# CloudFormation: Enable minimal S3 Block Public Access on the bucket
Resources:
  ExampleBucket:
    Type: AWS::S3::Bucket
    Properties:
      PublicAccessBlockConfiguration:
        IgnorePublicAcls: true        # Critical: ignores any public ACL grants (AllUsers/AuthenticatedUsers)
        RestrictPublicBuckets: true   # Critical: restricts buckets with public policies to same-account/service principals

Other

1In the AWS Console, go to S3 and open the bucket <example_resource_name>
2Select the Permissions tab
3Under Block public access (bucket settings), click Edit
4Check only:
5- Ignore public ACLs (true)
6- Restrict public buckets (true)
7Click Save changes and confirm

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.iam.lib.policy import is_policy_public
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_access(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 public."
                    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
                                ):
                                    report.status = "FAIL"
                                    report.status_extended = f"S3 Bucket {bucket.name} has public access due to bucket ACL."

                        # 4. Check bucket policy
                        if bucket.policy is not None and is_policy_public(
                            bucket.policy, s3_client.audited_account
                        ):
                            report.status = "FAIL"
                            report.status_extended = f"S3 Bucket {bucket.name} has public access due to bucket policy."
                    findings.append(report)
        return findings