ECS Task Roles via SSRF: Turning Metadata Into Cloud Access
EC2 instance metadata gets most of the press. ECS tasks have their own story. When a task role is attached, the agent exposes temporary credentials to the container. If your SSRF can reach that metadata path, you inherit whatever the task was supposed to use for S3, SQS, or Secrets Manager.
The finding is the chain: SSRF → credential material → demonstrable cloud action. Either half alone is weaker.
Find the metadata surface
On Fargate and modern ECS, containers often talk to 169.254.170.2 for task credentials. Relative paths and IPv6 variants show up in older writeups; verify what the target platform actually serves. Your SSRF gadget might be a URL fetch, a webhook tester, a PDF renderer, or an image downloader.
Probe carefully:
- Does the app follow redirects to link-local addresses?
- Are private IP literals blocked but DNS names that resolve to
169.254.0.0/16allowed? - Does a proxy allowlist miss the ECS credential endpoint?
- Can you hit
http://169.254.170.2through an open redirect inside the same trust zone?
I've seen filters that block 169.254.169.254 and forget the ECS address. That gap is the whole ticket. DNS rebinding and decimal IP encodings are worth a short attempt when literal link-local strings are rejected; stop if the program forbids aggressive networking tests.
Credential retrieval without drama
Once you can hit the credential endpoint, request only what you need for proof. Prefer listing role name fields and calling sts:GetCallerIdentity with the returned keys over exfiltrating long-lived secrets from the account. Rotate expectations: these creds expire; capture timestamps.
If a token header is required before credential retrieval, your SSRF must also obtain and replay it. Document whether a single blind fetch is enough or whether a multi-step browser-like client is needed. Blind SSRF that only triggers a DNS callback is not yet task-role theft. Full response body control—or an out-of-band channel that returns headers and JSON—is what turns the chain on.
Watch for task roles versus execution roles. The execution role pulls images and writes logs; the task role is what the app code uses. Stealing the wrong one still matters, but the impact story differs. Say which ARN you got.
Bound the blast radius
Map the task role's permissions from observed API errors or from infra-as-code in scope. Common high-impact grants:
- Read from a data bucket
- Publish to an internal queue
- Decrypt with a KMS key used for app secrets
- Invoke internal Lambdas
Prove one. Upload a canary object, send a canary queue message to a queue you were told is in-scope for testing, or read a non-sensitive configuration object. Do not ransack customer tables "to show severity."
If AccessDenied meets you on every action, the credentials are still a finding when paired with a clear privilege map from Terraform—but live proof of one successful call is what speeds triage.
Hardening notes that belong in the report
Recommend egress controls that block link-local metadata from app containers, task roles scoped to exact ARNs and prefixes, and network policies that keep user-controlled fetchers off the metadata path. Moving secrets to injected env files does not help if the same SSRF can hit an internal admin API instead—fix the fetch primitive.
SSRF into ECS credentials is still one of the cleanest cloud pivots in bounty work. Keep the proof small and the privilege story precise.