Cloud Misconfig

The $270 Million Misconfiguration

How One SSRF Request Turned a Misconfigured Firewall Into a 106-Million-Record Breach

Capital One's headquarters tower in Tysons, Virginia, at dusk.
Capital One's headquarters tower in Tysons, Virginia. Photo: Lluck002 / Wikimedia Commons, licensed CC BY-SA 4.0 (cropped).
Vector
SSRF against a misconfigured WAF, chained to AWS IAM credential theft
Impact
~106M individuals exposed; ~140K SSNs and ~80K bank accounts among them
Disclosed
Jul 29, 2019 — $80M OCC fine + $190M settlement, both final
Apophis coverage
Cloud penetration testing (AWS) — IAM & metadata-service exposure

What happened

In March 2019, an attacker gained access to more than 100 million Capital One credit card customer and applicant records stored in Amazon Web Services. The intrusion itself took place over two days, March 22–23. Capital One's own monitoring didn't catch it — the breach sat undiscovered for roughly four months, until an outside tip in mid-July 2019 pointed the company to data that had been posted publicly. Capital One notified federal law enforcement within days and disclosed the breach to the public on July 29, 2019.

The scale, once it was tallied, was substantial: approximately 106 million individuals across the United States and Canada. For the full set, that meant names, addresses, zip and postal codes, phone numbers, email addresses, dates of birth, and self-reported income and credit scores. For a smaller subset — about 140,000 people — it meant Social Security numbers, and for about 80,000 more, linked bank account numbers. Capital One's own statement was specific that no credit card account numbers or log-in credentials were compromised, which is one reason the incident is remembered less for what was stolen than for how casually it was taken.

The person responsible was not a nation-state group or an organized crime ring. She was a former cloud infrastructure engineer who had once worked for the cloud provider Capital One relied on, and she posted identifying details about the intrusion on GitHub and in a Slack channel — which is how the tip reached Capital One, and eventually the FBI, in the first place. She was convicted on federal computer fraud charges in 2022. Capital One, separately, paid an $80 million fine to the Office of the Comptroller of the Currency in 2020 and reached a $190 million class-action settlement with affected customers, which received final court approval in September 2022.

None of that — the size, the eventual legal outcomes, even the fact that the attacker effectively narrated her own crime — is really the point. The point is what she actually had to do to get in. It wasn't much, and the four-month gap between intrusion and discovery is its own lesson: nothing about the access pattern itself tripped an alarm inside Capital One. The breach surfaced because of an outside tip, not because the environment noticed something was wrong.

How it worked

The entry point was a Server-Side Request Forgery (SSRF) vulnerability in a web application firewall (WAF) sitting in front of Capital One's AWS infrastructure. SSRF is a class of vulnerability where an attacker tricks a server into making requests on their behalf — requests the server is trusted to make, to places the attacker themselves isn't supposed to be able to reach directly. The WAF was internet-facing by design. What it could reach on the inside was the mistake.

Every AWS EC2 instance has access to something called the Instance Metadata Service (IMDS) — an internal-only endpoint an instance can query about itself, primarily to fetch temporary security credentials for whatever IAM role is attached to it. That's how AWS lets an application authenticate to other AWS services without a hardcoded password baked into the code. It's a genuinely useful mechanism, and it depends entirely on nothing outside the instance ever being able to reach it.

The SSRF flaw broke that assumption. The attacker used it to make the misconfigured WAF itself issue the metadata request, and the WAF obliged — handing back temporary AWS credentials for its own attached IAM role. Those credentials were the second failure, and the more consequential one: the role was significantly over-permissioned relative to what a WAF actually needs to do its job. Instead of being scoped narrowly, it could list and read the contents of Capital One's S3 storage buckets — more than 700 of them, spanning years of accumulated data.

From that point on, nothing about the attack required further exploitation. No second vulnerability, no privilege escalation, no lateral movement in the sense security teams usually mean it. The attacker had valid, temporary, legitimately-issued AWS credentials, and she used them the way any authorized script would: she asked S3 what was in every bucket that role could see, and S3 answered.

Laid out as a chain, the whole thing is four steps, and only the first one is a genuine vulnerability — the rest is the environment simply doing what it was configured to do:

  1. An SSRF flaw in the WAF lets a crafted request reach an internal-only endpoint the WAF should never have been able to reach on the attacker's behalf.
  2. That endpoint is the EC2 Instance Metadata Service, and it hands back temporary credentials for the WAF's own attached IAM role — correctly, exactly as designed, to whatever is asking.
  3. The role's permissions are broader than the WAF's job requires — it can list and read arbitrary S3 buckets, not just the narrow set of actions a firewall needs.
  4. Nothing downstream checks whether the caller holding those credentials is the WAF doing its job or an attacker who obtained them through it. The credentials are valid, so S3 answers.

The pattern here — SSRF reaching a cloud metadata endpoint, then an over-permissioned IAM role turning momentary credential access into broad, standing data access — was common enough across the industry that AWS's own response went beyond Capital One. AWS later introduced IMDSv2, a session-oriented version of the metadata service built specifically to make this exact SSRF-to-credential-theft chain much harder to execute, by requiring a token fetched via a separate, harder-to-forward request before any metadata call succeeds. A platform-level redesign like that doesn't happen in response to a freak one-off; it happens because a lot of environments were exposed the same way.

Why this matters beyond one company

It's tempting to read a breach like this as a story about one firewall, misconfigured once, by one company, years ago. That reading misses what made it dangerous: every piece of the failure — an internet-facing component with more network reach than it needs, an IAM role with more permission than its workload needs, a metadata service that answers whoever asks — is a configuration choice, not a bug in any one product. Configuration choices get made the same way, by the same kinds of teams, on new infrastructure every day.

The specific defenses have improved since 2019 — IMDSv2 among them — but defenses that ship as an option, not a default, only help the organizations that turn them on and audit that they stayed on. An environment provisioned before the option existed, or one where a role's permissions quietly grew broader over years of "just add this policy to unblock the deploy," ends up in the same place Capital One's WAF was: reachable, over-trusted, and unaudited until something goes wrong.

That's the part a point-in-time audit or an annual penetration test tends to miss. A cloud environment's permission graph doesn't stay still. It drifts every time a role gets a new policy attached to unblock someone's Tuesday, and nobody circles back to narrow it again. A test scheduled once a year checks the graph as it existed on test day — not as it exists six months later, after a dozen small, individually-reasonable changes.

It's also worth naming plainly what kind of finding this is for a regulated business. Capital One is a nationally chartered bank, which is exactly why the Office of the Comptroller of the Currency had authority to fine it directly, on top of the civil settlement. An exposed IAM role isn't just a security gap — for an organization under banking-regulator oversight, it's the kind of gap that turns into a regulatory enforcement action even before it turns into a class-action settlement.

How Apophis maps to this

A misconfigured WAF with an over-permissioned IAM role — a Confirmed-tier finding class, not a hypothetical

Apophis's cloud penetration testing mode probes AWS environments for exactly this pattern: internet-facing components with a reachable metadata service, paired with an IAM role carrying more permission than the component actually needs. This isn't a theoretical attack path requiring a novel exploit chain — it's a directly testable configuration issue, the same category of finding Apophis surfaces continuously rather than once a year. Apophis enumerates an environment's internet-facing components, checks whether each one's attached IAM role is scoped appropriately against what that component does, and confirms whether a metadata endpoint is reachable from somewhere it shouldn't be trusted with broad credentials — the same chain this breach depended on from end to end. Run against an environment carrying this misconfiguration, Apophis would likely have surfaced and rated it as a Critical finding long before an outside tip became the only thing standing between it and public exposure. Because the drift problem above is a scheduling problem as much as a technical one, Apophis's continuous engagement mode re-runs this same check on an ongoing basis rather than once a year, so a role that grew over-permissioned in month four doesn't wait for an annual test in month twelve to surface.

Confirmed
apophis — engagement
$ apophis --target aws-prod-vpc --prompt cloud
[RECONNAISSANCE] 14 internet-facing components enumerated
[ENUMERATION] IMDS reachable from waf-edge-01, IAM role attached
[CRITICAL] Over-permissioned IAM role  waf-edge-01 → s3:ListBucket, s3:GetObject (700+ buckets)
[OBJECTIVE] 1 validated finding — 11 min

Is this exposure sitting in your environment right now?

Apophis tests for this exact class of finding.

Schedule Your Free Demo