The OWASP Top 10 was written for traditional web applications. But in the cloud, the attack surface shifts. SQL injection becomes Lambda event injection. Broken access control becomes misconfigured IAM. And SSRF — barely a footnote in traditional web security — becomes the most dangerous cloud-specific attack vector.
This article maps each OWASP category to its cloud-native equivalent.
OWASP Top 10 in the Cloud Era
A01: Broken Access Control
Traditional: User accesses another user’s data by changing an ID in the URL. Cloud twist: IAM misconfigurations, overly permissive S3 bucket policies, cross-account access without proper controls.
// ❌ S3 bucket policy — allows anyone to read
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::customer-data/*"
}
// ✅ Restricted to specific role
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789:role/ApiServer"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::customer-data/*"
}Cloud defenses: IAM least privilege, S3 Block Public Access, resource-based policies with explicit principals.
A02: Cryptographic Failures
Traditional: Transmitting sensitive data over HTTP, weak hashing. Cloud twist: Unencrypted S3 buckets, unencrypted RDS instances, KMS key mismanagement.
# Check all S3 buckets for encryption
aws s3api list-buckets --query 'Buckets[].Name' --output text | \
xargs -I {} sh -c 'echo -n "{}: "; aws s3api get-bucket-encryption --bucket {} 2>/dev/null || echo "NOT ENCRYPTED"'Cloud defenses: KMS encryption for all data at rest, TLS 1.2+ for all data in transit, SCPs enforcing encryption.
A03: Injection
Traditional: SQL injection via form inputs. Cloud twist: Lambda event injection — untrusted data arrives from SQS, S3 events, API Gateway, and other AWS services.
# ❌ Lambda event injection — S3 key used in shell command
import subprocess
def handler(event, context):
bucket = event['Records'][0]['s3']['bucket']['name']
key = event['Records'][0]['s3']['object']['key']
# Attacker uploads file named: "; rm -rf / #"
subprocess.run(f"process-file {bucket}/{key}", shell=True) # INJECTION!
# ✅ Safe — use parameterized approach
def handler(event, context):
bucket = event['Records'][0]['s3']['bucket']['name']
key = event['Records'][0]['s3']['object']['key']
subprocess.run(["process-file", f"{bucket}/{key}"], shell=False)Cloud defenses: Input validation on all event sources, parameterized commands, WAF on API Gateway.
A04: Insecure Design
Cloud twist: Architectures that don’t consider security boundaries — flat VPCs, shared service accounts, no network segmentation between microservices.
Cloud defenses: Threat modeling with STRIDE, network policies in Kubernetes, separate AWS accounts for prod/staging/dev.
A05: Security Misconfiguration
This is the #1 cloud vulnerability. More breaches happen from misconfiguration than from exploits.
# Common misconfigurations to check
# 1. Public security groups
aws ec2 describe-security-groups \
--filters "Name=ip-permission.cidr,Values=0.0.0.0/0" \
--query 'SecurityGroups[].{ID:GroupId,Name:GroupName}'
# 2. IMDSv1 enabled (allows SSRF credential theft)
aws ec2 describe-instances \
--query 'Reservations[].Instances[?MetadataOptions.HttpTokens!=`required`].{ID:InstanceId,State:State.Name}'
# 3. Public RDS instances
aws rds describe-db-instances \
--query 'DBInstances[?PubliclyAccessible==`true`].{ID:DBInstanceIdentifier}'Cloud defenses: AWS Config rules, Checkov/tfsec on all Terraform, enforce IMDSv2, Security Hub enabled.
A06: Vulnerable and Outdated Components
Cloud twist: Vulnerable base images in Docker, outdated Lambda runtimes, unpatched AMIs.
Cloud defenses: Trivy image scanning, Dependabot auto-updates, ECR image scanning, Lambda runtime deprecation alerts.
A07: Identification and Authentication Failures
Cloud twist: Overly long-lived access keys, no MFA on IAM users, shared credentials between services, no token rotation.
# Find access keys older than 90 days
aws iam generate-credential-report
aws iam get-credential-report --query 'Content' --output text | \
base64 -d | awk -F, 'NR>1 && $9!="N/A" && $11!="N/A" {print $1,$9}'Cloud defenses: Enforce MFA, use IAM roles instead of access keys, rotate credentials automatically, short-lived tokens.
A08: Software and Data Integrity Failures
Cloud twist: Unsigned Docker images, unverified CI/CD artifacts, no provenance for deployed code.
Cloud defenses: cosign for image signing, SLSA provenance, Kubernetes admission controllers that verify signatures.
A09: Security Logging and Monitoring Failures
Cloud twist: CloudTrail not enabled in all regions, no VPC Flow Logs, no alerts on high-risk API calls.
Cloud defenses: Multi-region CloudTrail, CloudWatch alarms for security events, centralized SIEM, automated alerting.
A10: Server-Side Request Forgery (SSRF)
This is the most dangerous cloud-specific vulnerability. SSRF in a cloud environment gives attackers access to the Instance Metadata Service (IMDS) and temporary IAM credentials.
# The classic SSRF attack in cloud
# Attacker sends: url=http://169.254.169.254/latest/meta-data/iam/security-credentials/
# ❌ Vulnerable code — fetches any URL
import requests
def handler(event, context):
url = event['queryStringParameters']['url']
response = requests.get(url) # SSRF!
return {'statusCode': 200, 'body': response.text}
# ✅ Defended — allowlist + IMDSv2
import requests
from urllib.parse import urlparse
ALLOWED_HOSTS = ['api.example.com', 'cdn.example.com']
def handler(event, context):
url = event['queryStringParameters']['url']
parsed = urlparse(url)
if parsed.hostname not in ALLOWED_HOSTS:
return {'statusCode': 403, 'body': 'Blocked'}
if parsed.hostname.startswith('169.254.') or parsed.hostname == 'metadata.google.internal':
return {'statusCode': 403, 'body': 'Blocked'}
response = requests.get(url, timeout=5)
return {'statusCode': 200, 'body': response.text}Critical defense: Enforce IMDSv2 on all EC2 instances. IMDSv2 requires a session token that can’t be obtained via a simple GET request, effectively blocking most SSRF-based credential theft.
# Enforce IMDSv2 on all instances
aws ec2 modify-instance-metadata-options \
--instance-id i-1234567890abcdef0 \
--http-tokens required \
--http-endpoint enabledCloud-Specific Mitigations Summary
| OWASP | Cloud Defense | AWS Service |
|---|---|---|
| A01 | IAM least privilege | IAM Access Analyzer |
| A02 | Encrypt everything | KMS, ACM |
| A03 | Validate all event inputs | WAF, input validation |
| A05 | Continuous compliance | Config, Security Hub |
| A06 | Scan everything | ECR scanning, Trivy |
| A09 | Log everything | CloudTrail, VPC Flow Logs |
| A10 | IMDSv2 + URL allowlists | Instance metadata config |
Key Takeaways
- SSRF is the #1 cloud risk — enforce IMDSv2 on every instance, no exceptions
- Misconfiguration > exploitation — most cloud breaches are misconfig, not zero-days
- Lambda event injection is real — treat all event sources as untrusted input
- IAM IS access control — broken IAM = broken access control in the cloud
- Encrypt by default — KMS for rest, TLS for transit, no exceptions
- Log everything, alert on anomalies — CloudTrail is your cloud security backbone











