Capital One - SSRF → IMDSv1 → Over-Privileged IAM Role → 106M Record S3 Exfiltration
A former AWS engineer exploited a misconfigured WAF via server-side request forgery to reach the EC2 instance metadata service, stealing temporary IAM role credentials. An over-privileged role then granted access to 700+ S3 buckets containing 106 million customer records. The attack ran undetected for 117 days and directly caused AWS to build IMDSv2.
Thompson built a custom tool to scan the internet for EC2-hosted web applications that would relay requests to the AWS instance metadata service at 169.254.169.254. SSRF was not in ModSecurity's default detection rule set and had to be explicitly configured.
Why SSRF wasn't blocked: Not in default WAF rules - required manual configuration
Scanning approach: Automated - targeted multiple AWS-hosted organisations
The WAF was misconfigured, running in logging-only mode or bypassable, so Thompson sent crafted HTTP requests containing the IMDS endpoint as the target URL. The WAF relayed these server-side, making the EC2 instance itself issue the metadata request.
IMDSv1 behaviour: No authentication - any GET request from the instance is served
WAF failure: Relayed SSRF payload rather than blocking it
IMDSv1 returned the temporary AWS credentials (AccessKeyId, SecretAccessKey, SessionToken) for the "ISRM-WAF-Role" attached to the EC2 instance. No token, header, or authentication was required, just a GET request to the metadata path from within the instance (which the SSRF provided).
Credentials returned: AccessKeyId + SecretAccessKey + SessionToken
Key problem: The role had S3 permissions far beyond what a WAF needs
With the stolen AWS credentials, Thompson used the CLI to list all S3 buckets accessible to the ISRM-WAF-Role. The role had been granted sweeping S3 list and read permissions, far beyond what a WAF firewall function ever needed, in violation of least privilege at the design level.
Result: 700+ buckets listed including Capital One customer data stores
Root failure: IAM role permissions never reviewed against principle of least privilege
Thompson synced S3 bucket contents to external storage using aws s3 sync. Approximately 30GB over multiple sessions: 100M US and 6M Canadian credit card application records, 140,000 SSNs, 80,000 bank account numbers, credit scores, and transaction history.
Data exfiltrated: 106M records, 140K SSNs, 80K bank accounts, credit/financial history
Detection gap: GuardDuty not enabled; S3 access logs not monitored for volume anomalies
Thompson bragged about the breach on GitHub and in Slack and IRC channels under the handle "erratic." A member of the public noticed the posts, reviewed the data, and filed a responsible disclosure with Capital One on July 17, 2019. No internal monitoring caught the breach during the 117-day dwell period: not GuardDuty, not S3 access logs, not IAM anomaly detection.
Monitoring failures: No GuardDuty · No S3 volume alerts · No anomalous IAM activity detection
Arrest: Paige Thompson, July 29, 2019
