ECS-cape: Hijacking IAM Privileges in Amazon ECS
Black Hat USA 2025 · Day 1 · Briefings
Overview
Security researcher Naor Aziz discovered that any container running inside an Amazon ECS EC2 cluster can impersonate the ECS agent — the control plane bridge running on every container instance — using publicly accessible instance metadata and an internal AWS protocol called ACS, obtaining IAM credentials for every other task and task execution role running on the same EC2 instance, with no evidence of the hijack in CloudTrail logs. ---

Key moments
- 5:59 Discovery: ECS agent uses WebSocket with 'sendcredentials=true' — credentials in plaintext
- 10:00 Root cause: AWS only checks ECS Poll permission to accept WebSocket; no instance binding
- 12:00 Exploit: container registers fake container instance, AWS sends all task credentials to it
- 13:59 IMDS abuse: use instance metadata to obtain instance role for fake container registration
- 17:59 Scope: attacker receives credentials for both task role AND task execution role of all co-tenants
- 21:59 Multi-tenancy impact: steal IAM credentials from other tenants on shared ECS cluster
- 23:59 Demo: ECSEscape task deletes S3 bucket belonging to co-tenant task
- 27:59 CloudTrail logs show deletion attributed to legitimate S3 task, not ECSEscape — forensics blind
ECS-cape: Hijacking IAM Privileges in Amazon ECS
Speaker: Naor Aziz, Software Developer and Security Researcher, Sweet Security
Conference: Black Hat USA 2025 — August 6-7, 2025, Mandalay Bay, Las Vegas
YouTube: https://www.youtube.com/watch?v=UV-hS-DTeik
Reading Time: ~8 minutes
Type: Briefing
TL;DR
Security researcher Naor Aziz discovered that any container running inside an Amazon ECS EC2 cluster can impersonate the ECS agent — the control plane bridge running on every container instance — using publicly accessible instance metadata and an internal AWS protocol called ACS, obtaining IAM credentials for every other task and task execution role running on the same EC2 instance, with no evidence of the hijack in CloudTrail logs.
Introduction
Amazon ECS (Elastic Container Service) is AWS's managed container orchestration platform, positioned as a simpler alternative to Kubernetes. A core security promise of ECS is task-level IAM isolation: each task runs with its own IAM role, and — according to AWS documentation at the time of the research — "a container never has access to credentials that are intended for another container that belongs to another task." That promise, it turns out, was not enforced at the platform level.
The vulnerability, which Aziz named ECS-cape (a portmanteau of ECS and escape), allows a single compromised container to step outside its assigned IAM boundary, reach an internal AWS control plane protocol, and receive the plaintext temporary credentials of every other task and task execution role co-located on the same EC2 instance. In multi-tenant environments where different customers or application tiers share the same container instances, the implications escalate to full tenant-to-tenant credential hijacking. AWS acknowledged the findings and updated their documentation; the fix — where it exists — lies primarily with operators rather than the platform.
Background: IAM, ECS, and the ECS Agent
▶ Watch: IAM and ECS Architecture Overview (02:00)
Understanding ECS-cape requires clarity on two IAM roles that every ECS task carries:
- Task role: The role available to containers within the task, defining what AWS resources those containers can access (S3, DynamoDB, Secrets Manager, etc.).
- Task execution role: A separate role used exclusively by ECS itself — not the containers — to pull container images and inject secrets (e.g., database credentials) into the task as environment variables. The task is never supposed to see this role's credentials directly.
In ECS EC2 mode (as opposed to Fargate), tasks run on EC2 instances managed by the operator. Each instance runs two critical components: the Docker daemon, which executes containers, and the ECS agent, an open-source Go binary that acts as a bridge between the AWS control plane and the instance. The ECS agent authenticates to the control plane using the EC2 instance's instance role — a role with elevated permissions including RegisterContainerInstance, DiscoverPollEndpoint, and other internal ECS APIs. This unit — the EC2 plus ECS agent — is referred to as a container instance.
The Discovery Story: Chasing a Service Name
▶ Watch: Discovery Story — Inspecting the ECS Agent (06:00)
Aziz was building a detection and response sensor at Sweet Security when his manager asked him to instrument ECS task monitoring. He noticed that Docker container labels contained nearly all the metadata he needed — cluster ARN, task ARN, task definition family — but were missing the service name. To get it, the ECS agent must have been calling some API the labels didn't expose.
Setting up a proxy to inspect the ECS agent's outbound traffic, Aziz observed it connecting to the ECS service over a WebSocket with the query parameter send_credentials=true. A captured message from that WebSocket showed live task credentials passing over the wire. The question immediately formed: could a container impersonate the ECS agent and receive those credentials too?
The ECS agent is fully open source on GitHub, which proved invaluable for understanding its authentication flow.
The ECS Agent Authentication Flow
▶ Watch: ECS Agent Protocol Deep Dive (10:01)
The ECS agent performs three steps to establish its credential-receiving WebSocket:
- RegisterContainerInstance: Calls the
RegisterContainerInstanceAPI using the instance role, receives a container instance ARN. AWS documentation notes this API is "only used by the ECS agent and not for use outside of the agent" — which, as Aziz observed, only made him more interested. - DiscoverPollEndpoint: Calls the
DiscoverPollEndpointAPI to receive a poll endpoint URL (an internal AWS endpoint URL specific to the region and availability zone). Same documentation warning, same reaction. - ACS WebSocket: Uses the container instance ARN plus identifiers gathered from IMDS and the task metadata endpoint (version 4) to construct a WebSocket request to the poll endpoint URL. With
send_credentials=truein the query parameters, the control plane streams IAM credentials for all tasks and task execution roles running on the instance via the Agent Communication Service (ACS) protocol.
ACS is an undocumented internal AWS protocol. Aziz found it carries task metadata (including the service name he originally sought), agent-level directives, configuration updates, and — most importantly — the full IAM credentials for every task and task execution role on the instance.
The ECS-cape Attack: Impersonating the Agent
▶ Watch: ECS-cape Exploitation Flow (14:03)
The attack exploits the fact that in ECS EC2 mode, IMDS (Instance Metadata Service) is accessible to every task on the instance by default. IMDS returns the instance role credentials — the same credentials the ECS agent uses. This means any task can call DiscoverPollEndpoint just like the real agent.
The remaining challenge was constructing a valid ACS WebSocket request, which requires several identifiers: cluster ARN, container instance ARN, agent version, and agent hash. Most identifiers were available via IMDS and the task metadata endpoint (v4). The container instance ARN was the missing piece — until Aziz discovered the Container Introspection API, an endpoint the ECS agent exposes to all tasks on the instance that returns the cluster name, container instance ARN, agent version, and agent hash.
With all identifiers assembled, a task can:
- Use IMDS to obtain instance role credentials.
- Call
DiscoverPollEndpointto get the poll endpoint URL. - Query the Container Introspection API for the container instance ARN and agent identifiers.
- Construct and connect a valid ACS WebSocket, authenticating as the ECS agent.
- Receive plaintext, already-assumed IAM credentials for every task role and task execution role on the instance.
The credentials arrive pre-assumed by AWS — no AssumeRole call is made by the attacker, so CloudTrail logs attribute the credential issuance to the legitimate task or ECS itself, not to the attacking container. There is no evidence of the hijack in CloudTrail.
Impact: From Privilege Escalation to Tenant Escape
▶ Watch: Impact Analysis and Multi-Tenancy Scenario (20:03)
The live demo featured a three-task cluster: an "ECS Escape task" (with a deny-all IAM policy), an "S3 control task" (with full S3 access), and a "database task" (with no task role but a task execution role able to read from AWS Secrets Manager). From the deny-all ECS Escape container:
- Running
aws s3 rb s3://bucketlasvegas2025returned Access Denied. - Running the
ecs-escapetool (an open-source CLI written in Rust, published on GitHub) logged hijacked credentials for all co-located tasks and deleted the bucket successfully. - The tool also extracted the plaintext value of the secret from Secrets Manager — a credential the attacking container had no direct access to — using the task execution role credentials of the database task.
In multi-tenant environments, this becomes a cross-tenant attack: a task belonging to Tenant A can obtain the IAM credentials of any task belonging to Tenant B if both run on the same EC2 instance. The attacker gains access not only to the credentials but to all internal ECS metadata exposed through the ACS protocol, which was previously inaccessible.
AWS Response and Documentation Update
▶ Watch: AWS Acknowledgment and CloudTrail Evasion (26:09)
AWS declined to patch the platform behavior, classifying the ECS agent as running within the "consumer security boundary" — meaning the instance role and its permissions are the operator's responsibility to secure. AWS updated their official documentation to reflect this: the previous statement that "a container never has access to credentials that are intended for another container" has been revised to acknowledge that "tasks running on the same EC2 instance may potentially access credentials belonging to other tasks on that instance."
An official statement on the AWS Security Blog thanked Sweet Security and Naor Aziz for the research.
Mitigations
▶ Watch: Mitigations and Best Practices (28:10)
Aziz outlined four operator-side mitigations:
- Disable IMDS access at the task level (not the instance level, which would break the ECS agent). AWS provides IP tables rules to block task-level IMDS access — these are documented in official guidance. This removes the attacker's path to instance role credentials and is the most effective mitigation.
- Do not use
AmazonEC2ContainerServiceForEC2Roleas the instance role policy directly for tasks. This policy includesRegisterContainerInstance,DiscoverPollEndpoint, and other internal ECS permissions that enable the attack. - Minimize task role and task execution role permissions. Apply least privilege: give each task only what it needs, and give each task execution role access only to the specific secrets that task requires.
- Separate high-privilege and low-privilege workloads — either across different ECS clusters or at the EC2 instance level. The same applies to multi-tenant systems: different tenants should run in separate clusters or, at minimum, on separate instances.
Notable Quotes
"What if I told you that a single container running inside your cloud environment can use an internal AWS protocol and hijack the credentials of another more powerful container on the same machine? In some cases, that's all it takes to take over your entire cloud environment."
— Naor Aziz, ▶ 00:00
"AWS documentation said that a container never has access to credentials that are intended for another container that belongs to another task. That's the promise of task roles — isolation, security, separation. But as you can see, using this technique, a task can actually reach beyond that boundary."
— Naor Aziz, ▶ 18:03
"I get the role plaintext credentials. And if I look at CloudTrail logs, the user agent and the identity that assumes the role are ECS itself. So it's selfie. There's no mention of the attacker container, no sign of the hijack."
— Naor Aziz, ▶ 18:03
"Please, task level hardening is everything. This is the only way to prevent this kind of vulnerability."
— Naor Aziz, ▶ 32:10
Key Takeaways
- IMDS is accessible to all ECS tasks on an EC2 instance by default, giving every container the instance role credentials — the same credentials the ECS agent uses to authenticate to the AWS control plane.
- The Container Introspection API (an ECS agent–exposed endpoint available to all tasks) provides the container instance ARN needed to construct a valid ACS WebSocket, completing the impersonation chain.
- The ACS protocol streams pre-assumed IAM credentials for all co-located tasks and task execution roles, bypassing IAM isolation entirely — and because no
AssumeRoleis invoked by the attacker, CloudTrail shows no anomaly. - Task execution roles are not safe from task-level access: many teams assume execution roles are ECS-only, making them overprivileged and a high-value target for this technique.
- The primary mitigation is disabling IMDS access at the task level via IP tables rules; AWS has not patched the underlying platform behavior and has instead updated its documentation to remove the isolation guarantee.
Slides: No slide PDF was available for this talk.
Reviews
Dr. Zero (Offensive Security Researcher) — STRONG ACCEPT
Aziz found that ECS's IAM isolation guarantee — explicitly documented by AWS — was never enforced at the platform level, and any container on an EC2 instance can impersonate the ECS agent, drain credentials from every co-tenant task via the undocumented ACS WebSocket, and leave no fingerprint in CloudTrail. AWS's response was to update the documentation. Welcome to cloud security.
Heather Calloway (CISO) — MUST SEE
A compromised container in Amazon ECS EC2 mode can impersonate the ECS agent, use an internal undocumented AWS protocol, and receive plaintext IAM credentials for every co-located task — with no evidence in CloudTrail. AWS declined to patch and updated their documentation to remove the isolation guarantee they previously claimed.