S3 bucket is not publicly accessible to Everyone or Authenticated Users
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 Cloudprowler aws --checks s3_bucket_public_accessRecommendation
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=trueTerraform
# 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 principalsOther
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