Cloud infrastructure has changed the threat model for every organization. The perimeter is no longer defined by your firewall — it's defined by your IAM policies, your S3 bucket ACLs, and your security group rules. Misconfigure any of them and the exposure is global and immediate.
These 7 misconfigurations account for the vast majority of AWS-related security incidents. All of them are detectable from the external attack surface.
1. Public S3 Buckets
The most overexposed vulnerability category in AWS. Public S3 buckets have been the source of data exposures affecting healthcare records, financial data, source code, and customer PII across virtually every industry.
What it looks like externally:
GET https://company-backup.s3.amazonaws.com/ → HTTP 200, XML bucket listing
GET https://company-assets.s3.amazonaws.com/customer_data.csv → HTTP 200, data
Why it happens: Teams create buckets for internal use and rely on the AWS console "public" indicator without understanding that IAM policies, ACLs, and bucket policies interact in complex ways. A bucket can appear "private" via one control path while being accessible via another.
Prevention:
# Account-level Block Public Access — prevents all public access regardless of bucket policies
aws s3control put-public-access-block \
--account-id {account-id} \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
Enable this at the account level. It overrides bucket-level settings. If you legitimately need public buckets (static website hosting, public assets), create a separate dedicated AWS account for them.
2. Overly Permissive Security Groups
Security groups are AWS virtual firewalls. The default configuration in many tutorials and automation templates opens ports to 0.0.0.0/0 (all of the internet) for convenience — and those ports stay open.
External detection: EASM tools scan for open ports across your known IP ranges. Common high-risk open ports:
| Port | Service | Why It's High Risk |
|---|---|---|
| 22 | SSH | Brute-forceable; key exposure risk |
| 3389 | RDP | Windows remote desktop; ransomware target |
| 3306 | MySQL | Database direct access |
| 5432 | PostgreSQL | Database direct access |
| 6379 | Redis | Often no auth, in-memory data |
| 27017 | MongoDB | Often no auth by default |
| 9200 | Elasticsearch | No auth by default in older versions |
| 8080 | Development server | Often debug mode enabled |
| 8888 | Jupyter Notebook | No auth by default |
Prevention: Security groups should follow the principle of least privilege. Open only what's needed. Databases and internal services should never be in security groups with 0.0.0.0/0 ingress rules on their data ports.
3. IMDSv1 Enabled (SSRF → Credential Theft)
IMDSv1 (Instance Metadata Service version 1) is accessible at http://169.254.169.254/ from any process running on the instance. An SSRF vulnerability in any application on the instance can retrieve the instance's IAM credentials.
IMDSv1 credential retrieval:
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
# → {"role-name": "ec2-production-role"}
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-production-role
# → {"AccessKeyId": "...", "SecretAccessKey": "...", "Token": "..."}
These credentials are temporary but valid for several hours. An attacker with these credentials has whatever permissions the EC2 instance's IAM role has.
Fix: Enforce IMDSv2, which requires a PUT-based session token before any metadata retrieval, making SSRF exploitation significantly harder:
aws ec2 modify-instance-metadata-options \
--instance-id i-xxx \
--http-tokens required
Or in your Terraform:
metadata_options {
http_tokens = "required"
}
4. Wildcard IAM Policies
IAM policies that grant "Action": "*" or "Resource": "*" violate least privilege and create the conditions for catastrophic lateral movement when any credential is compromised.
The blast radius problem:
If an EC2 instance with s3:* on * is compromised, an attacker can access every bucket in your account. If it also has iam:*, they can create new admin users and establish persistent access.
Detection from external perspective: Not directly detectable until compromise. Detection requires internal AWS Config rules or security tooling.
Prevention:
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::specific-bucket/*"
}
AWS IAM Access Analyzer identifies overly permissive policies automatically. Enable it in every region.
5. Exposed .git Directories
Web servers that serve .git/ directories publicly expose the entire version history of your codebase — including commits that contained credentials, API keys, or internal hostnames before they were removed.
Detection:
GET https://yourapp.com/.git/HEAD → HTTP 200 (exposed)
GET https://yourapp.com/.git/config → exposes remote URL
GET https://yourapp.com/.git/COMMIT_EDITMSG → exposes commit history
Tools like git-dumper can reconstruct the entire repository from an exposed .git/ directory.
Why it happens: Deployments that copy the entire project directory (including .git/) to web server document root, or Docker images built from the working directory without excluding .git/.
Fix: Configure your web server to deny access to .git/:
location ~ /\.git {
deny all;
return 404;
}
Or ensure your deployment pipeline never includes .git/ in the web root.
6. Default VPC and Insecure Default Configuration
AWS creates a default VPC in every region with public subnets and open internet gateway. Resources launched in the default VPC without explicit security group restrictions may be directly internet-accessible.
More critically: the default security group for the default VPC allows all inbound traffic from other instances in the same security group. In the default VPC, many teams' instances are in the same security group — creating an implicit east-west trust relationship.
Prevention: Don't use the default VPC for production workloads. Create application-specific VPCs with:
- Private subnets for databases and internal services
- Public subnets only for load balancers and NAT gateways
- Explicit security group rules
7. Public RDS Instances
RDS (Relational Database Service) instances with PubliclyAccessible: true are directly reachable from the internet. Combined with a weak password or default credentials, this is a direct path to database exfiltration.
Detection: EASM tools scanning for open database ports (3306, 5432, 1433) on IP ranges associated with AWS regions can identify publicly accessible RDS endpoints.
Fix: RDS instances should never have PubliclyAccessible: true unless there is a specific architectural requirement. Access to RDS should go through:
- Private VPC subnets (no internet gateway route)
- VPN or AWS PrivateLink for external access
- Bastion hosts for admin access
aws rds modify-db-instance \
--db-instance-identifier mydb \
--no-publicly-accessible \
--apply-immediately
PentestCheck EASM Engine scans for all 7 of these misconfiguration patterns across your external IP range. Cloud infrastructure findings include direct remediation steps for AWS, GCP, and Azure.