AWS IAM Role Chaining and Privilege Escalation Paths in Production

How attackers exploit AWS role chaining to escalate privileges in production.

Summary

How attackers exploit AWS role chaining to escalate privileges in production.

AWS IAM Role Chaining and Privilege Escalation Paths in Production.

Why role chaining exists and what happens at each hop

Role chaining is what happens when you take temporary credentials from one assumed IAM role and use them to assume a second role through STS AssumeRole. It sounds like a small technical detail, but it's the connective tissue of most serious AWS architectures oneuptime.com. The canonical version looks like this: a developer sitting in Account A assumes a hub role in Account B, and from there reaches a production role in Account C. Nobody in Account A ever touches production directly, which is precisely the point. An EC2 instance profile assuming a cross-account role to reach some shared resource sitting elsewhere produces the same pattern in service-to-service contexts, with no human involved at all.

Each hop is a clean break, not an inheritance. New credentials get issued at every step (a fresh AccessKeyId, SecretAccessKey, and SessionToken tuple), and the old ones aren't carried forward, they're swapped out entirely. Run through a boto3 script or a bash one-liner and you'll see the pattern repeat three times over: assume, receive, assume again, with each step producing a new AccessKeyId/SecretAccessKey/SessionToken tuple. What actually enforces the boundary is the trust policy sitting on the target role. The production role in Account C doesn't trust "everyone in Account A." It trusts the hub role's ARN, specifically, and nothing else. That specificity is the entire security model in miniature.

The exact mechanism that enforces a controlled path to production is, hop by hop, also compounding whatever permissions get handed along the way. A gate that only opens for the right key is still a gate that opens. Once an attacker holds the right key, or forges something that looks enough like it, the same architecture built for control becomes the architecture that carries them straight through.

The AWS-imposed constraints that shape both legitimate use and abuse

AWS puts a hard ceiling on chained sessions of one hour, regardless of whatever MaxSessionDuration was configured on the role detection.fyi. That's not a setting anyone chose. It's baked into the service. EC2 instance profiles get a pass on this limit, since EC2 instance profiles assuming roles are not subject to this chaining duration limit.

This produces a familiar, almost comic operational headache. Long-running CI/CD pipelines and data-processing jobs die at the one-hour mark for no reason anyone can immediately explain, and the standard fix engineers reach for is to just re-invoke AssumeRole and grab a new token. Which is fine, until you notice that's the exact refresh behavior that turns chaining into a persistence mechanism. The workaround for reliability and the technique for maintaining a foothold are, mechanically, the same API call.

AWS also caps chain depth at ten roles in a single sequence, a limit few teams ever bump into but one that exists precisely because someone, somewhere, tried to go further oneuptime.com. That's the root cause behind most chaining failures in practice, and it's also, not coincidentally, a great way to accidentally build the exact broad-trust condition an attacker is hoping to find.

None of this is cosmetic. The one-hour refresh cycle isn't just an annoyance for engineers waiting on a pipeline, it's a security signal: every AssumeRole call issues a new session token, so an attacker holding a chain has to keep re-authenticating, over and over, to keep the foothold alive Rhino Security Labs. Elastic's detection rule documentation flags this behavior as a pattern to watch for Rhino Security Labs. The constraint AWS built for reliability doubles as the constraint that gives defenders a repeating, detectable heartbeat oneuptime.com.

How a low-privilege credential becomes the starting point for escalation

Nobody starts with the crown jewels. These are the documented initial access vectors as of 2026, and none of them require anything exotic.

The first move after that is almost always the same: aws sts get-caller-identity. It's a diagnostic, not an attack. That's exactly why it works so well as a first step. It confirms the credential is live, reveals the account ID and the user's ARN, and logs to CloudTrail as GetCallerIdentity, indistinguishable from a developer checking their own session. Nothing about that log entry screams intrusion.

From there it's enumeration: a burst of ListAttachedUserPolicies, GetPolicyVersion, and ListRolePolicies calls, often from the same source IP, or automated tools like enumerate-iam and Pacu quietly mapping out what's possible by testing which read-only APIs succeed and which fail. The cause is almost embarrassingly simple: if you can modify your own permissions, or the permissions of anything you already control, you can eventually reach permissions nobody meant for you to have. It's less a hack than a loophole in how trust gets delegated.

The scale of the exposure is not small. Wiz Research found that 82% of organizations unknowingly hand third parties highly privileged roles in their cloud environments, and the average cost of a cloud breach hit $4.4 million in 2025. Those two numbers together explain why this subject gets researched as hard as it does: the door is left open far more often than anyone realizes, and walking through it is expensive. Leaked access keys can be found hardcoded in GitHub repos, CI/CD pipelines, and Docker images. SSRF can hit the EC2 Instance Metadata Service at 169.254.169.254 to steal the attached role's temporary credentials. Phishing can harvest AWS SSO session tokens.

The specific escalation paths that role chaining enables or amplifies

Rhino Security Labs has catalogued more than twenty distinct IAM escalation methods, and separate lab testing in 2026 confirmed that all twelve classic scenarios from the IAM-Vulnerable framework were exploitable in an unrestricted environment. The techniques vary in mechanics, but a handful appear repeatedly in the wild.

The master primitive is iam:PassRole. By itself it does nothing, it's an inert permission that just lets you hand a role to a service. Chained with a compute action, it becomes one of the most dangerous escalation levers available. Swap the compute target and the pattern holds: PassRole plus lambda:CreateFunction and lambda:InvokeFunction lets an attacker pass a privileged role to a brand-new function and then invoke it with code they wrote themselves. AWS Glue offers a third variant, PassRole plus glue:CreateDevEndpoint, which spins up a development endpoint carrying a privileged role, and once an attacker injects their own SSH public key, those credentials are available to anything running on that endpoint inside the VPC. Simple in principle. Frequently skipped in practice.

Then there's the quieter route: iam:CreatePolicyVersion. An attacker with permission to modify their own attached policy can create a new version granting Action: on Resource:, and set it as the default in the same call, no separate iam:SetDefaultPolicyVersion permission required. The forensic sting is in the cleanup: do the work, roll the policy back to its original version, and most audits, which check what's currently attached rather than combing through every historical version, will see nothing out of place.

Existing Lambda functions offer a similarly quiet path. No new resources, no new role assumptions, just code injected into a function that's already trusted and already has a role attached, sitting there waiting for its next invocation. It's a supply-chain attack, just one that happens entirely inside the AWS account rather than upstream in a dependency.

The blunt-force option is iam:AttachRolePolicy, or its user-facing cousin: attach AdministratorAccess directly to the compromised identity and skip the subtlety altogether. It logs as AttachUserPolicy, fully visible in CloudTrail, but visibility only matters if a human or a detection rule is actually looking. And there's iam:UpdateAssumeRolePolicy, which targets the trust policy itself. Widen the Principal field, say to the entire account root ARN instead of a specific role, and suddenly any identity in that account can assume the role. Missing or misconfigured condition keys turn that widened trust into an open door with no lock at all.

Every single one of these techniques uses legitimate, documented AWS API calls, tying them together more than any individual technique does. Misconfiguration alone is sufficient. One remediation lever is to restrict PassRole with a Resource ARN list or use the iam:PassedToService condition key.

How default IAM roles silently extend the attack surface

Some of this attack surface isn't created by attackers or even by sloppy engineers. It ships by default. In April 2025, Aqua researchers Yakir Kadkoda and Ofek Itach found that AWS services including SageMaker, Glue, EMR, and Lightsail automatically create or recommend default IAM roles during initial setup, and those roles grant overly broad permissions, full S3 access among them, silently opening privilege escalation and cross-service attack paths Rhino Security Labs.

The specifics are almost comically consistent. SageMaker, when set up under the Single user or Quick Setup option for a domain, automatically creates an execution role named AmazonSageMaker-ExecutionRole-<Date&Time>, carrying a custom policy that's functionally equivalent to AmazonS3FullAccess. Glue's first console access spins up AWSGlueServiceRole, which in some configurations gets paired with that same AmazonS3FullAccess policy, though it isn't attached automatically in every case. EMR follows the same script, generating a default AmazonEMRStudio_RuntimeRole_<Epoch-time> role with AmazonS3FullAccess baked in.

Full S3 access sounds like a modest convenience Rhino Security Labs. It's a lateral movement engine. A role carrying AmazonS3FullAccess can read and write every bucket in the account, including buckets that CloudFormation, EMR, and SageMaker all quietly depend on. An attacker can pivot from one service to another without ever needing to assume another role. Aqua's own attack scenario traced exactly that path: a malicious Hugging Face model imported into SageMaker leads to arbitrary code execution, which pivots to Glue through a shared S3 bucket, which yields Glue's job IAM credentials, which escalates into full account compromise via CloudFormation template injection.

AWS's response was to modify the AmazonS3FullAccess policy attached to these default service roles, while confirming that CDK, Glue, EMR, and SageMaker were "operating as expected," classifying the behavior as design rather than defect. The roles worked exactly as intended, and that was the problem.

Stale roles make all of this worse over time. A forgotten role that's still active, still carrying broad permissions, is a favorite target, and any role that can modify other IAM policies or spin up new roles can hand an attacker de facto administrative control. Default trust has quietly become the new misconfiguration. Organizations can audit what they built by hand, but they can't audit what AWS built for them without knowing to look oneuptime.com.

Diagram: Aqua's Attack Path: SageMaker to Full Account Compromise. Visualizes: Illustrate the five-hop lateral movement chain that Aqua Security researchers demonstrated inside a single AWS account, using only the default roles AWS creates during…

The AI agent layer: how AWS Bedrock AgentCore introduces a new role-chaining surface

Privilege escalation on AWS has moved oneuptime.com. AWS privilege escalation has shifted from IAM policy abuse to service-based execution and AI-powered orchestration, and Bedrock AgentCore is the newest, most actively researched frontier in that shift.

Unit 42's disclosure on the AgentCore Code Interpreter reads like a IAM permission with a wildly understated name. Any principal holding bedrock-agentcore:InvokeCodeInterpreter can execute code under the agent's own IAM role, not the caller's, and there's no resource-based policy control restricting who gets to do that. The Code Interpreter's microVM exposes its temporary execution-role credentials through an internal metadata service, MMDS, and Sonrai Security researchers demonstrated a string-filter bypass that let those credentials get exfiltrated straight past the sandbox boundary. The attribution problem that follows means actions taken with those stolen credentials get logged to CloudTrail under the Code Interpreter's own identity, not the attacker's.

BeyondTrust's Phantom Labs took a wider architectural view and found four separate entry points into the same underlying problem. AgentCore places an IAM execution role on MMDS inside a Firecracker microVM, the same virtualization primitive EC2 has relied on for years, nothing new there. What's new is that AgentCore exposes four distinct entry points into that microVM rather than one, and a single permission, bedrock-agentcore:InvokeAgentRuntimeCommand, is enough to drop a root shell inside and read the role's credentials directly.

Default configurations recur as a problem in the AgentCore starter toolkit. Researchers demonstrated listing S3 bucket contents, extracting credentials, and pulling PII and financial data out from inside what was supposed to be an isolated sandbox.

The reason all of this accelerates the underlying role-chaining problem rather than just adding to it: AI agents inherit human-scale IAM permissions but act on them at machine speed. They don't pause to second-guess a suspicious instruction, and they don't notice when a session is being abused. That one-hour token refresh, the same signal that gives human-operated chains a detectable heartbeat, disappears into background noise inside an agent runtime that never sleeps. The disclosure timeline that Unit 42 reported ran as follows: reported to AWS Security November 17, 2025 → AWS responded November 18, 2025 → AWS requested more details December 14, 2025 → AWS provided clarifications January 28, 2026 (Rhino Security Labs). BeyondTrust found Bedrock "Shadow Roles" as a starter toolkit default. The Amazon Bedrock AgentCore starter toolkit ships an overly permissive default IAM role granting broad S3, DynamoDB, and Secrets Manager access. AWS rated the parallel DNS issue CVSS 7.5, initially declined a permanent fix, before later remediating the DNS exfiltration vector after public disclosure, updated documentation, and recommended customers migrate to VPC mode.

What CloudTrail records across a chain (and where the gaps are)

Some of the escalation techniques covered earlier leave fairly clean fingerprints. AttachUserPolicy and AttachRolePolicy events are fully visible, as is a burst of enumeration calls, rapid-fire ListAttachedUserPolicies, GetPolicyVersion, and ListRolePolicies requests from a single source IP, assuming anyone's built a detection rule watching for that pattern in the first place. GetCallerIdentity at the front of an attack chain is visible too, but it's visible in the sense that it looks exactly like every legitimate developer session ever logged, which makes it useless as a standalone signal.

AgentCore complicates the picture in a way traditional IAM abuse never quite managed to. When credentials get exfiltrated from the Code Interpreter's microVM and used elsewhere, the resulting actions log under the Code Interpreter's own identity rather than the attacker's. The chain is technically there, sitting in CloudTrail, fully auditable in the sense that every API call gets recorded somewhere. It's just forensically misleading, pointing an investigator toward a sandboxed AI service that did nothing wrong, while the actual attacker sits several steps removed from the log entry that would have named them. Every AssumeRole call generates a CloudTrail event, and certain fields matter for chain reconstruction.

Sources

  1. How to Chain IAM Role Assumptions (Role Chaining)
  2. AWS IAM Privilege Escalation to Data Exfil: The Full Attack Chain — Hive Security
  3. AWS STS Role Chaining
  4. elastic.co
  5. AWS IAM Privilege Escalation – Methods and Mitigation
  6. aquasec.com
  7. unit42.paloaltonetworks.com
  8. beyondtrust.com

More in Cloud Permissions