Skip to content

SSRF to IMDS Credential Theft

2 min read Created Aug 10, 2026 Last updated Aug 10, 2026

IMDSv1 answers metadata requests without a session token, so any code that can make an outbound HTTP request from the instance, including an SSRF in a hosted app, can read IAM role credentials from 169.254.169.254. IMDSv2 requires a PUT token request first, which most SSRF primitives cannot perform. Confirming which mode an instance enforces tells you whether the credential-theft path is open.

The control is MetadataOptions.HttpTokens: optional means IMDSv1 is still accepted and the instance is exposed, required means IMDSv2 only.

Data reachable through IMDSv1 without a token:

  • IAM role temporary credentials (/iam/security-credentials/)
  • Instance identity document and region
  • User data scripts, often containing secrets
  • Network configuration and MAC addresses

Check From the AWS API

With credentials that can call EC2, query the metadata options directly. This is the reliable, non-intrusive check.

┌──(kali㉿kali)-[~]
└─$ aws ec2 describe-instances --profile $PROFILE \
--query 'Reservations[].Instances[].{Id:InstanceId,Tokens:MetadataOptions.HttpTokens,HopLimit:MetadataOptions.HttpPutResponseHopLimit}' \
--output table
-------------------------------------------------
|                DescribeInstances              |
+----------+-----------+--------------------------+
| HopLimit | Id        | Tokens                   |
+----------+-----------+--------------------------+
|  1       | i-0abc... | optional                 |
|  2       | i-0def... | required                 |
+----------+-----------+--------------------------+

optional confirms the weakness. A HttpPutResponseHopLimit above 1 is a secondary finding: it lets containers a hop away from the host reach IMDS, widening the blast radius even on IMDSv2.

Sweep every region, since the default profile only queries one:

┌──(kali㉿kali)-[~]
└─$ for region in $(aws ec2 describe-regions --profile $PROFILE --query 'Regions[].RegionName' --output text); do
echo "== $region =="
aws ec2 describe-instances --profile $PROFILE --region $region \
--query 'Reservations[].Instances[?MetadataOptions.HttpTokens==`optional`].InstanceId' --output text
done

Confirm From the Instance

With a shell on the host, a token-less request that returns data proves IMDSv1 is live. A response here means the same request works through an SSRF.

user@host ~ $ curl -s -o /dev/null -w '%{http_code}\n' http://169.254.169.254/latest/meta-data/
200

200 confirms IMDSv1. If the instance enforces IMDSv2 the same request returns 401, and you would need a token request first, covered in EC2 Instance Metadata Service.

Where It Leads

Confirmed IMDSv1 with an attached instance profile is a direct route to role credentials. Turning an application SSRF into stolen credentials is covered in SSRF to IMDS Credential Theft.