← All field notes
awsssrfcloud securityimds

From SSRF to stolen cloud credentials: the EC2 metadata attack

An SSRF flaw can read EC2 instance-role credentials from the metadata service and replay them from anywhere. Here is the attack, the detection, and why IMDSv2 stops it.

Attack flow
1Find an SSRF in a web app
2Hit the EC2 metadata service
3Read the instance role credentials
4Call AWS as the role
5Access S3 and pivot
Seen in the wildCapital One breach (2019)Cloud access brokers

A server-side request forgery bug in a web app is not just a web bug in the cloud. It can become full cloud-credential theft, because the app can be tricked into reading the instance metadata service.

The attack

The attacker abuses an SSRF flaw to make the application fetch http://169.254.169.254/latest/meta-data/iam/security-credentials/. The metadata service returns the EC2 instance role’s temporary credentials. The attacker then replays those credentials, which start with the ASIA prefix, from outside AWS to read S3 and reach whatever the role can touch. This is the Capital-One-class attack. In ATT&CK terms it is T1552.005, Unsecured Credentials: Cloud Instance Metadata API.

Why it works

IMDSv1 requires no session token, so any GET-based SSRF reaches it. Instance roles are also frequently over-privileged, so a stolen role token unlocks far more than the workload needs.

How to detect it

GuardDuty raises InstanceCredentialExfiltration.OutsideAWS when instance-role credentials are used from a non-AWS IP. In CloudTrail, the tell is an ASIA session key used from a source address outside your VPC.

How to contain and fix it

You cannot delete a single temporary session. Instead, attach a deny policy conditioned on aws:TokenIssueTime to invalidate every credential issued before now, and enforce IMDSv2 with HttpTokens required and a hop limit of one. IMDSv2 requires a token obtained by a PUT request that a typical SSRF cannot send. Across the org, require IMDSv2 at launch with an SCP, scope instance roles to least privilege, turn on S3 Block Public Access, and enable CloudTrail data events for sensitive buckets.

Practice it

We built this scenario in GraphLattice Range, including the session-revocation call that catches teams who try to reset a key that does not exist.