flawopen.com/Incidents/Capital One SSRF

Capital One: the SSRF that turned a web request into cloud credentials

Critical — 100M+ records CWE-918: Server-Side Request Forgery Disclosed July 2019
ELI5

A company has a receptionist who will fetch documents from any address you give them. Inside the building, there is an unmarked door that hands out the company's master keys to anyone who knocks — the designers assumed only staff could ever reach it. You ask the receptionist to knock on that door for you. They do, because it is just an address, and they bring you the keys.

Key terms on this page
SSRF
Server-Side Request Forgery — tricking a server into making an HTTP request to a destination the attacker chooses. The request carries the server's network position and identity, not the attacker's.
instance metadata service (IMDS)
A special link-local address (169.254.169.254) reachable only from inside a cloud instance, which returns configuration data — including, critically, temporary credentials for the instance's attached IAM role.
IMDSv2
A revised version of that service requiring a session token obtained via a PUT request with a hop limit, which defeats the simple GET-based SSRF that made this attack possible.

What happened

In July 2019 Capital One disclosed a breach affecting roughly 100 million individuals in the United States and a further 6 million in Canada — credit card application data spanning years, including names, addresses, dates of birth, self-reported income, and a smaller volume of Social Security and bank account numbers.

The intrusion did not begin with stolen credentials or malware. It began with a misconfigured web application firewall running on an EC2 instance that could be induced to make outbound requests on an attacker's behalf. That is the whole primitive: make this server fetch a URL for me.

The kill chain

1. SSRF against the metadata endpoint

The attacker used the SSRF to make the instance request http://169.254.169.254/latest/meta-data/iam/security-credentials/ — an address only reachable from inside the instance. The metadata service answered, because from its perspective the request came from the instance itself.

2. Harvest the role's temporary credentials

That endpoint returned a temporary access key, secret key and session token for the IAM role attached to the instance. The attacker now held valid AWS credentials with whatever permissions that role carried.

3. Use the permissions the role actually had

The role was permitted to list and read S3 buckets. The attacker ran ListBuckets and then GetObject — ordinary, authorised-looking API calls — and exfiltrated the contents. Nothing further needed to be exploited; the credentials were legitimate.

Regulators subsequently found the underlying failures to be organisational as much as technical: inadequate identification and remediation of the misconfiguration, and insufficient detective controls to catch the anomalous access.

THE VULNERABLE PATTERN
# Server fetches a user-supplied URL.
# The classic SSRF sink.
url = request.args["target"]
resp = requests.get(url)
return resp.text

# target=http://169.254.169.254/latest/
#        meta-data/iam/security-credentials/
# → returns live AWS credentials
DEFENCE IN DEPTH
# 1. Allowlist destinations. Resolve the
#    hostname, then check the resolved IP
#    is public — not loopback, private,
#    or link-local (169.254.0.0/16).

# 2. Re-check after redirects. A 302 to
#    the metadata IP defeats naive checks.

# 3. Enforce IMDSv2 so a plain GET
#    cannot retrieve credentials at all.

# 4. Scope the IAM role down. It should
#    not have been able to read those
#    buckets in the first place.

Why this incident reshaped cloud defaults

Capital One is the reason SSRF stopped being treated as a second-tier bug class. Before it, SSRF was often triaged as an information-disclosure nuisance. After it, the industry understood that in a cloud environment SSRF is a credential-theft primitive — because the cloud platform itself puts a credential vending machine at a fixed, well-known, unauthenticated address inside every instance.

AWS introduced IMDSv2 in November 2019, requiring a PUT to obtain a session token and defaulting to a low IP hop limit. Both changes specifically break the "one blind GET" pattern this attack relied on. Equivalent hardening exists across other cloud providers.

The lessons that actually transfer

FAQ

Does IMDSv2 make SSRF safe?

No — it removes one very high-value target. SSRF can still reach internal admin interfaces, databases, Kubernetes APIs, and other services that trust the network position of the caller. It remains a serious bug class on its own merits.

Would a WAF have stopped this?

The vulnerable component in this case was a web application firewall, which is a useful reminder that security appliances are applications too. Filtering rules can raise the cost of exploitation but do not address the underlying design, which is that a server will fetch whatever address it is told to.

Related reading

Sources