Skip to content

AWS_ASSUME_ROLE

Copy page

Summary

Forestall ACL Alias AWS_ASSUME_ROLE
Edge Type Attack Path
Affected Object Types IAM Users, IAM Roles, AWS Services
Exploitation Certainty Certain
AWS IAM Action / Condition sts:AssumeRole on the target role

Description

AWS_ASSUME_ROLE records that a principal can call sts:AssumeRole against a target IAM role and receive temporary credentials scoped to that role’s permissions.

The caller gets back AccessKeyId, SecretAccessKey, and SessionToken, valid for up to 12 hours. Those credentials carry the full permission set of the assumed role, which may far exceed what the caller normally has.

Two things must both be true for this path to work:

  1. The source identity has sts:AssumeRole allowed in its own policies.
  2. The target role’s trust policy lists the source identity as a permitted principal.

Cross-account assumption is standard practice in multi-account AWS architectures. The target role in Account B lists an Account A principal in its trust policy. An attacker who controls that Account A identity can pivot to Account B without any credentials native to it.

Common condition keys for restricting this path are aws:MultiFactorAuthPresent, sts:ExternalId, aws:SourceIp, and aws:PrincipalOrgID. Missing or misconfigured conditions are where most over-permissive chains come from.

Identification

AWS CLI

Pull the trust policy to see who can assume the role:

aws iam get-role --role-name TargetRole \
--query 'Role.AssumeRolePolicyDocument'

Simulate whether a specific identity can assume the role:

aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:user/AnalystUser \
--action-names sts:AssumeRole \
--resource-arns arn:aws:iam::123456789012:role/TargetRole

Find all roles whose trust policies list a specific principal:

aws iam list-roles --query 'Roles[*].[RoleName,AssumeRolePolicyDocument]' \
--output json | python3 -c "
import json, sys
roles = json.load(sys.stdin)
for name, policy in roles:
doc = policy if isinstance(policy, dict) else json.loads(policy)
for stmt in doc.get('Statement', []):
p = stmt.get('Principal', {})
if 'arn:aws:iam::123456789012:user/AnalystUser' in str(p):
print(name)
"

Exploitation

Assume the target role:

aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/TargetRole \
--role-session-name AttackerSession

Export the returned credentials:

export AWS_ACCESS_KEY_ID=<AccessKeyId>
export AWS_SECRET_ACCESS_KEY=<SecretAccessKey>
export AWS_SESSION_TOKEN=<SessionToken>

Verify the assumed identity:

aws sts get-caller-identity

Cross-account trust policies often require an ExternalId. If you have or can guess the value, pass it:

aws sts assume-role \
--role-arn arn:aws:iam::999999999999:role/CrossAccountRole \
--role-session-name AttackerSession \
--external-id KnownExternalId

Mitigation

  • Trust policies should name specific principals. Remove anything that isn’t actively used.
  • Use aws:PrincipalOrgID to keep cross-account assumptions inside your organization.
  • Add aws:MultiFactorAuthPresent: 'true' as a condition on sensitive roles.
  • Treat sts:ExternalId as a shared secret for third-party access. Don’t expose it in docs or error messages.
  • Never use "Principal": "*" in a trust policy. Any authenticated AWS principal can attempt the assumption.
  • Set MaxSessionDuration to the shortest viable session length.

Detection

Watch CloudTrail for AssumeRole activity:

  • Event source: sts.amazonaws.com
  • Event name: AssumeRole
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRole \
--query 'Events[*].{Time:EventTime,Actor:Username,Role:Resources[0].ResourceName}'

Signals worth investigating:

  • Cross-account assumptions from an account you don’t recognize.
  • Session names that break your naming convention. Automated tools produce consistent patterns; attackers often don’t.
  • Repeated AccessDenied on AssumeRole calls, a sign of trust policy enumeration.
  • Admin, deploy, or break-glass role assumptions outside business hours.

References

Was this page helpful?

Thank you for your feedback.