Capital One AWS IAM SSRF Exploit and Metadata Credential Theft

How misconfigured cloud defenses turned a WAF into a credential theft tool.

Summary

How misconfigured cloud defenses turned a WAF into a credential theft tool.

The Capital One breach of 2019 did not involve a zero-day exploit, malware, or brute force. It succeeded because three cloud-native misconfigurations, each unremarkable on its own, lined up into a single working chain: a misconfigured web application firewall that could be tricked into making requests on the attacker's behalf, an unauthenticated metadata endpoint that handed over live credentials to anyone who asked, and an IAM role with far more reach than the WAF ever needed. Seven years later the case still gets taught because the pattern never stopped recurring; the same three-part structure appeared again in 2026 inside AI agent infrastructure. This piece is an anatomy of the chain, link by link, because understanding how it was built is the only way to know where to cut it.

How AWS EC2 instances carry embedded credentials that SSRF can reach

Every EC2 instance ships with a hardwired HTTP endpoint at 169.254.169.254, the Instance Metadata Service, or IMDS. Under IMDSv1 it answers a plain HTTP GET with no authentication required. Under IMDSv2 it requires a token first. Either way, IMDS exists to hand infrastructure automation the data it needs, including the live credentials for whatever IAM role is attached to the instance. It was built for convenience, not as a security boundary, and it is only reachable from inside the instance or container task, which is precisely the assumption that made it so exploitable once something inside that instance could be puppeted from outside.

Retrieving those credentials takes two requests. The first asks IMDS for the name of the IAM role attached to the instance:

GET
→ returns: ISRM-WAF-Role

The second appends that role name and gets back a complete, working credential set:

GET
→ returns: AccessKeyId, SecretAccessKey, Token

Those credentials are not decoys or limited sandboxed tokens. They carry exactly the permissions assigned to the role, nothing more and nothing less. If that role has s3:GetObject on *, whoever holds the credentials can read every object in every S3 bucket in the account. In a pre-cloud, on-premise environment, a request-forgery bug was a serious problem with a limited blast radius. On AWS, the same bug pointed at the metadata endpoint turns into full credential theft, and from there, into account takeover.

What SSRF Is

Server-side request forgery lets an attacker make a server issue HTTP requests to destinations of the attacker's choosing, including internal addresses the public internet was never supposed to reach. It is catalogued as CWE-918 and ranked as OWASP A10:2021, and it shows up anywhere an application fetches a URL on a user's behalf without checking where that URL actually points: image proxies, webhook validators, link-preview generators, PDF renderers, any API that takes a url parameter at face value.

Now consider what happens when the vulnerable component is a web application firewall. A WAF sits in front of everything by design, trusted by the network architecture to inspect and forward traffic. A WAF's trusted position in the network architecture is the reason an SSRF bug inside one is so much worse than an SSRF bug inside a typical application server. A request from the WAF to 169.254.169.254 looks, to IMDS, exactly like a request from the instance itself, because that is what IMDS is built to serve. It also looks, to most monitoring tooling, like ordinary metadata service traffic, because nothing was watching for that specific destination. The WAF had no validation on where its outbound requests could go, no rule blocking the link-local range, no network ACL standing between it and the metadata endpoint. The component built to stop attacks became the one that carried one out. That is the irony sitting at the center of this entire case: the security control was the attack surface.

The attack sequence Thompson executed, step by step

Paige Thompson, a former AWS engineer, had the architectural knowledge to recognize this chain immediately, though nothing about it required insider access. The federal indictment states that she exploited the misconfigured WAF using SSRF on March 22, 2019. The first request retrieved the name of the attached IAM role. The second request, sent to the metadata path for that role, returned a full credential set, AccessKeyId, SecretAccessKey, and session token, valid for the entire scope of whatever that role was permitted to do.

From there the attack left the cloud entirely. Thompson configured the stolen credentials into the AWS CLI on an external system and ran aws s3 ls to enumerate the account's buckets, then began pulling down their contents. Every one of those API calls was fully authenticated and indistinguishable, from AWS's perspective, from a legitimate call made by Capital One's own infrastructure. The unauthorized access took place March 22 and 23, 2019. She was arrested July 29, 2019, and convicted in June 2022 on wire fraud and Computer Fraud and Abuse Act charges. The reach extended well past Capital One: roughly 30 AWS accounts were accessed in total, including ones belonging to the Ohio Department of Transportation, Vodafone, Michigan State University, and Ford Motor Company.

The three missing controls that each had to fail for the breach to succeed

Diagram: The Three-Link Chain: How Each Gap Had to Fail. Visualizes: Show a three-stage attack chain where every link had to fail for the breach to succeed.

Three separate controls were absent, and any single one of them, present and working, would have stopped or significantly contained the breach.

The first gap sat at the WAF layer. Nothing validated or restricted where the WAF's server-side requests could go, and no security group rule or network ACL blocked the instance from reaching the link-local metadata range, 169.254.0.0/16. Blocking that range at the network level would have made the credential-retrieval step impossible no matter how exploitable the SSRF bug in the application itself remained.

The second gap was IAM over-permissioning. The S3 access granted to the role was not scoped to specific buckets or key prefixes, and the policy carried no conditions restricting where requests could originate from. The same credentials the WAF needed to do its actual job also unlocked more than 700 data buckets. Scoping that role down to only what the WAF legitimately required would have contained the damage even after the credentials were stolen. This is textbook OWASP A01:2021, broken access control through excessive permission.

The third gap was detection. Thompson operated inside Capital One's AWS environment for roughly four months, and nothing in that window flagged the unusual API calls, the bulk S3 access, or the data transfer patterns that followed. Without behavioral baselining on what the role's credentials normally did, Thompson's activity read as ordinary traffic from a trusted source. A fourth, smaller failure sits alongside these three: Capital One's own internal audit process failed to catch the control weaknesses in its cloud environment before any of this happened, a governance failure that regulators would later treat as its own separate finding.

Why IMDSv2 Alone Does Not Close the Vulnerability

The standard response to this case is "upgrade to IMDSv2," and that response is incomplete. IMDSv2 requires a two-step handshake: a PUT request carrying an X-aws-ec2-metadata-token-ttl-seconds header to get a session token, followed by GET requests that use that token. The PUT request carries a hop limit that keeps it from traversing standard HTTP proxies, which does defeat a large share of common proxy-based SSRF attacks.

It does not defeat all of them. If a vulnerable application follows HTTP redirects, an attacker can redirect from a domain they control to 169.254.169.254, and the PUT request still executes from the application server itself, satisfying the hop limit and collecting a valid token. When the SSRF lives in application code rather than in a network proxy, the application makes the PUT request directly, and the hop limit is irrelevant. Organizations that keep http_tokens set to optional to avoid breaking legacy integrations leave IMDSv1 sitting open right next to IMDSv2. Misconfigured ECS tasks and Lambda environments carry their own residual token-hopping gaps even after a nominal IMDSv2 rollout.

IMDSv2 hardens one stage of a three-stage chain: the metadata-retrieval step. It does nothing about the SSRF vulnerability that let the attacker reach IMDS in the first place, nothing about an IAM role scoped too broadly, and nothing about the absence of monitoring that let stolen credentials operate for months before anyone noticed. Input validation and destination allowlisting govern whether a malicious request reaches internal resources. Least-privilege IAM limits what stolen credentials can actually do once they're out. Resource policies on S3 buckets add a second permission boundary independent of the role itself. Runtime monitoring and behavioral baselining catch credentials in active use before exfiltration finishes. None of these substitutes for the others, and the gap that mattered most in Capital One's case, the four months of undetected activity, is the one IMDSv2 was never built to close.

The U.S. Department of the Treasury's Office of the Comptroller of the Currency found that Capital One failed to establish effective risk assessment processes before migrating significant IT operations to the public cloud, and that its internal audit function failed to catch numerous control weaknesses and gaps in that environment. The OCC ordered Capital One to pay an $80 million fine and to appoint a Compliance Committee responsible for submitting periodic updates on remediation efforts. A separate class-action settlement added $190 million, pushing total financial exposure from litigation and regulatory action to nearly $300 million.

Thompson's conviction in June 2022 on wire fraud and Computer Fraud and Abuse Act violations initially brought a sentence of time served and five years of probation. A U.S. appeals court later overruled that sentence, citing the scale of the damage, described as the second-largest data breach in the U.S. at the time, and sent the case back to district court for resentencing. Federal prosecutors also noted that Thompson had planted cryptocurrency mining software on servers she accessed, which widened the criminal conduct beyond data theft alone.

AWS maintained throughout that the root cause was Capital One's own WAF configuration, not a flaw in AWS infrastructure. Regulators agreed in substance: the $80 million penalty held Capital One responsible for its own cloud governance and configuration failures, not AWS for the platform it provided. That outcome drew an explicit line under the shared-responsibility model that every organization running workloads in AWS, or any public cloud, now operates inside. Cloud misconfiguration stopped being treated as an IT incident and became a recognized category of safety-and-soundness violation for regulated financial institutions.

The SSRF-to-IMDS Chain in AI Agent Infrastructure

In 2026, researchers Tamir Ishay Sharbat and Lana Salameh of Zenity Labs disclosed a chain of security flaws in Amazon Bedrock AgentCore, called AgentCorruption, at SecTor in Toronto. Using a single prompt directed at one public-facing agent, the researchers used SSRF to query the Instance Metadata Service at 169.254.169.254 from inside the agent's execution environment, the same endpoint and the same mechanism Thompson had reached seven years earlier. AWS fixed the IMDSv1 exposure by moving AgentCore exclusively to IMDSv2 as of February 14, 2026. AWS fixed the excessive-permissions flaw separately before September 29, 2026, a slower turnaround that shows IAM over-permission is consistently the harder of the two issues to clean up.

AgentCorruption was a researcher disclosure. There is no evidence of in-the-wild exploitation, and it should not be read as a companion breach to Capital One in scale or consequence. What it demonstrates is structural recurrence rather than equivalence: a public-facing workload with SSRF-reachable access to IMDS, sitting behind an IAM role with reach far beyond what that workload actually needs, is the exact shape of the Capital One failure, reassembled inside a different product category. The credentials in the AgentCorruption case belonged to a default IAM role whose permissions extended well past the single agent that was compromised, reaching every AgentCore agent in the same account and region.

AI agents make this structural weakness worse, not better. An agent inherits human-scale IAM access and then acts on it at machine speed, across every service its role permits, without the hesitation or second-guessing that slows down a human operator doing the same thing. The gap that let Thompson operate undetected for four months, no visibility into what the credentials were actually doing, which API calls they made, whether that behavior deviated from any baseline, is the same gap sitting unresolved in most agent deployments today.

Breaking the chain: controls that address each stage of the SSRF-to-exfiltration sequence

No single control closes this chain. Defending against it requires independent measures at each of the three stages the Capital One breach exposed, application, identity, and detection, because a fix at one stage does not compensate for a gap at another.

Stage 1 breaks the SSRF itself, at the application and network layer. Any component that fetches URLs on behalf of users or other services needs destination validation and allowlisting. Outbound access to the link-local range, 169.254.0.0/16, should be blocked by security group rules and network ACLs on any internet-facing EC2 instance or container task. DAST scanning should test web-facing applications for SSRF before they ship. IMDSv2 enforcement, setting http_tokens to required, belongs here too, as a defense-in-depth layer that raises the cost of proxy-based attacks, not as the whole answer.

Stage 2 contains the blast radius through least-privilege IAM. Roles attached to internet-facing workloads should be scoped to the minimum set of resources and actions those workloads actually use; a WAF role has no business holding list-and-read access to every S3 bucket in the account. S3 bucket policies should restrict access by resource ARN and key prefix, with condition keys requiring requests to originate from specific VPC endpoints or IP ranges. The same discipline applies to AI agent roles: a Bedrock agent built to answer customer questions does not need account-wide permissions, and giving it those permissions anyway is the same mistake Capital One made with its WAF, wearing a different interface. Role permissions should be audited regularly against what the workload's own logs show it actually uses, with anything unused revoked.

Stage 3 detects credential use while it is still happening. Expected API call patterns for each IAM role should be baselined, so that bulk S3 listing or large data transfers from a WAF role trigger an alert immediately. CloudTrail should be enabled with alerting configured on AssumeRole activity, large GetObject volumes, and cross-region calls from instance-profile credentials. For AI agent deployments, that same behavioral monitoring needs to extend to every agent-issued API call: discovering every agent running in the environment, watching all approved AI traffic, flagging anomalous behavior and policy violations, and keeping a complete audit log of every action an agent takes. These are the controls that were missing from Capital One's environment in 2019, and they remain missing from most agent deployments in 2026.

Runtime enforcement, stopping a policy-violating API call before it completes, is what actually closes the gap that let Thompson operate for four months undetected. Logging what happened after the fact does not.

More in Breach Reconstruction