← All articles
Incident Response 9 min read

Capital One 2019: How a Single Misconfigured IAM Role Exposed 100 Million Records

A firewall appliance with excessive IAM permissions and an unpatched SSRF vulnerability gave an attacker temporary AWS credentials and unrestricted access to 700 S3 buckets.

CloudDefender Team ·
Capital One Attack Chain — July 2019AttackerExternal IPWAF EC2ModSecuritySSRF vulnIMDSv1169.254.169.254No auth requiredIAM RoleTemp credentialss3:* on *SSRF reqpivotsteal creds700 S3 Buckets106M records exfiltratedCredit apps, SSNs, accountss3:ListBucketss3:GetObjectWhat would have stopped this✓ IMDSv2 (hop limit = 1 blocks SSRF pivot)✓ Scoped IAM role (s3:GetObject on specific ARNs only)✓ WAF patch management (SSRF CVE was known)✓ GuardDuty (unusual cross-bucket enumeration)✓ S3 data event logging (s3:GetObject at scale)
The three-step attack chain: SSRF on the WAF → IMDSv1 credential theft → unrestricted S3 access.

On July 19, 2019, a former AWS engineer named Paige Thompson executed one of the largest financial data breaches in U.S. history. She accessed the personal information of over 106 million Capital One credit card applicants and customers — not by defeating sophisticated cryptography or exploiting a zero-day, but by chaining together three mundane misconfigurations that individually might have been dismissed as acceptable risk.

The technical details, later revealed in court proceedings and Capital One’s own disclosures, are required reading for anyone responsible for cloud security.

The three-step attack chain

Step 1 — SSRF on the WAF appliance. Capital One ran a web application firewall on an EC2 instance using ModSecurity. The instance had a Server-Side Request Forgery vulnerability — a class of bug where an attacker can coerce the server into making HTTP requests to internal destinations on their behalf. Thompson crafted a request that caused the WAF instance to make an outbound HTTP call to 169.254.169.254, the EC2 Instance Metadata Service (IMDS) endpoint. This address is link-local, meaning it is only accessible from within the instance itself — or, in an SSRF attack, by anything that can get the instance to make a request on its behalf.

Step 2 — Credential theft via IMDSv1. The IMDS endpoint returns metadata about the running instance, including the temporary IAM credentials associated with any attached IAM role. In 2019, IMDSv1 was the default, and it required no authentication — any process that could reach 169.254.169.254 could retrieve credentials. Thompson retrieved the temporary access key ID, secret access key, and session token for the IAM role attached to the WAF instance. The entire credential set was returned in a single unauthenticated HTTP GET request.

Step 3 — Unrestricted S3 access. The WAF instance’s IAM role had been granted overly broad S3 permissions — specifically s3:GetObject and s3:ListBucket across all resources (effectively Resource: "*"). With the stolen credentials, Thompson used standard AWS CLI commands to enumerate and download content from over 700 S3 buckets. Over approximately three months, she exfiltrated credit card applications going back to 2005, including names, addresses, credit scores, Social Security numbers, and linked bank account numbers for 106 million individuals.

Why each layer failed independently

The SSRF vulnerability was known — ModSecurity had patches available. But patch management on appliances is easy to defer, particularly when they are managed by a vendor or embedded in infrastructure tooling.

The IMDSv1 issue was architectural. AWS introduced IMDSv2 in 2019 precisely because IMDSv1’s lack of authentication made it trivially exploitable via SSRF. IMDSv2 requires a PUT request to obtain a session token before any metadata is retrievable, and that PUT cannot be forwarded by a standard SSRF because it requires a TTL=1 hop limit — meaning the request must originate from the instance itself, not be proxied through it.

The IAM role was the most preventable failure. A WAF appliance has no legitimate operational reason to list all S3 buckets or read objects from buckets unrelated to its function. The principle of least privilege would have limited this role to the specific bucket ARNs required for WAF log output — reducing the blast radius of any credential compromise from “all customer data” to “WAF logs.”

What detection looked like — and what was missing

Thompson’s activity went undetected for months. She conducted large-scale S3 enumeration and object retrieval using credentials that were legitimately issued to a known IAM role. From CloudTrail’s perspective, these were valid API calls.

What was missing: S3 data event logging was not enabled on the affected buckets. Data events — which capture s3:GetObject and s3:PutObject calls at the object level — are not enabled by default and carry additional cost. Without them, CloudTrail captured no record of the object-level reads. GuardDuty was not deployed, which would have flagged the cross-bucket enumeration pattern as anomalous. The breach was ultimately reported by a third party who noticed Thompson discussing it in a Slack channel.

The remediation playbook

Following the breach, Capital One and AWS provided clear guidance that has since become a baseline expectation:

Enforce IMDSv2. Set HttpTokens=required on all EC2 instances. In an AWS Organization, enforce this with a Service Control Policy that denies ec2:RunInstances when ec2:MetadataHttpTokens is not required. Existing instances can be migrated with modify-instance-metadata-options.

Scope IAM roles to the minimum necessary. Any role attached to a public-facing workload should be scoped to specific resource ARNs, not wildcards. Use IAM Access Analyzer to review existing policies and generate least-privilege replacements based on actual CloudTrail usage.

Enable S3 data event logging. For buckets containing sensitive data, enable object-level logging via CloudTrail. Feed these logs into CloudTrail Lake or an S3-based SIEM pipeline and alert on high-volume GetObject activity from a single identity.

Deploy GuardDuty. The Discovery:S3/TorIPCaller, Discovery:S3/AnomalousBehavior, and CredentialAccess:IAMUser/AnomalousBehavior finding types specifically address the patterns seen in this breach.

Patch appliances. WAFs, load balancers, and proxy appliances running on EC2 are software — they require the same patch discipline as any other workload. Automate vulnerability scanning against EC2 instances and track mean time to remediation for high-severity CVEs.

The $80 million lesson

Capital One paid $80 million in regulatory fines, along with hundreds of millions more in legal settlements, remediation costs, and customer notification. The technical root causes were a known vulnerability class, a two-decade-old metadata service design, and an IAM policy that was too broad. None required sophisticated tooling to prevent. They required discipline, scope, and the willingness to instrument what was already there.

The attacker did not defeat Capital One’s security. She walked through three doors that were left open.

CloudDefender

Defend your cloud. Continuously.

CloudDefender Suite gives security teams continuous posture management, threat detection, and compliance automation across AWS, Azure, and GCP — with zero false-positive fatigue.

Try CloudDefender →