IAM Privilege Escalation Detection
cloud-audit detects 64 IAM privilege escalation methods across 9 categories. This goes beyond static policy analysis -- it resolves actual escalation paths by combining IAM policies, trust relationships, and resource permissions.
The detection runs in two stages:
- Action-based detection (60 methods) -- matches each principal's effective permissions against a curated catalog of escalation patterns
- Lateral movement detection (4 methods) -- builds a directed graph of
AssumeRoletrust relationships and walks it from each non-admin principal toward admin roles
How It Works
- Calls
GetAccountAuthorizationDetailsto pull all IAM policies, roles, users, and groups - Resolves effective permissions per principal (inline + attached + group policies)
- Walks escalation paths: can this principal reach admin through any sequence of allowed actions?
- Reports each path with the specific escalation method and affected principal
No additional permissions beyond iam:GetAccountAuthorizationDetails and iam:SimulatePrincipalPolicy are required. The check is read-only.
Categories
1. IAM Self-Mutation (13 methods)
The principal can modify its own (or an assumable role's) permissions to grant itself admin access.
iam:CreatePolicyVersion- create new version of an attached policyiam:SetDefaultPolicyVersion- set a different policy version as defaultiam:AttachUserPolicy- attach managed policy to selfiam:AttachRolePolicy- attach managed policy to a roleiam:AttachGroupPolicy- attach managed policy to own groupiam:PutUserPolicy- attach inline policy to selfiam:PutGroupPolicy- modify group the principal belongs toiam:PutRolePolicy- attach inline policy to a roleiam:DeleteRolePolicy+sts:AssumeRole- remove blocking inline policy on assumable roleiam:DeleteUserPolicy- remove blocking inline policy on a useriam:DetachRolePolicy+sts:AssumeRole- detach blocking managed policy from assumable roleiam:DetachUserPolicy- detach blocking managed policy from a useriam:CreateServiceLinkedRole- create service-linked role with service-managed admin policies
2. Credential Access (8 methods)
The principal can obtain credentials for a more privileged identity, or bypass MFA defenses.
iam:CreateAccessKey- create access keys for another useriam:CreateLoginProfile- set console password for another useriam:UpdateLoginProfile- reset another user's passwordiam:AddUserToGroup- add self to a more privileged groupiam:UpdateAccessKey- re-enable a disabled access key for another useriam:DeactivateMFADevice- remove MFA from a user, bypass MFA-required policiesiam:DeleteVirtualMFADevice- delete a virtual MFA device, bypass MFA-required policiesssm:GetParameter- read secrets stored in SSM Parameter Store (DB credentials, API keys)
3. PassRole + Service (23 methods)
The principal can pass a privileged role to an AWS service that executes code, or swap the role on an existing instance profile.
Original (legacy) entries:
- PassRole + Lambda (
lambda:CreateFunction+lambda:InvokeFunction) - PassRole + EC2 (
ec2:RunInstances) - PassRole + ECS (
ecs:RegisterTaskDefinition+ecs:RunTask) - PassRole + Glue (
glue:CreateDevEndpoint) - PassRole + CloudFormation (
cloudformation:CreateStack) - PassRole + DataPipeline (
datapipeline:CreatePipeline)
Tier 1 additions (variants of services already covered):
- PassRole + Glue Job (
glue:CreateJob) - PassRole + Glue Job update (
glue:UpdateJob) - PassRole + Glue Session (
glue:CreateSession) - PassRole + ECS UpdateService (
ecs:UpdateService+ecs:RegisterTaskDefinition) - PassRole + ECS RegisterTaskDefinition (auto-deploy via service refresh)
- PassRole + CloudFormation UpdateStack (
cloudformation:UpdateStack) - PassRole + EC2 instance profile attach (
ec2:AssociateIamInstanceProfile) - PassRole + EC2 instance profile replace (
ec2:ReplaceIamInstanceProfileAssociation) - PassRole + Lambda event source mapping (
lambda:CreateEventSourceMapping) - Instance profile role swap (
iam:RemoveRoleFromInstanceProfile+iam:AddRoleToInstanceProfile) - no PassRole required
Tier 2 additions (new compute primitives):
- PassRole + CodeBuild (
codebuild:CreateProject+codebuild:StartBuild) - buildspec runs with privileged role - PassRole + AppRunner (
apprunner:CreateService) - container runs with privileged role - PassRole + SageMaker Notebook (
sagemaker:CreateNotebookInstance) - Jupyter root with privileged execution role - PassRole + SageMaker Processing Job (
sagemaker:CreateProcessingJob) - PassRole + SageMaker Training Job (
sagemaker:CreateTrainingJob) - PassRole + Bedrock Agent (
bedrock:CreateAgent) - agent invokes AWS APIs through tool use - PassRole + Step Functions (
states:CreateStateMachine) - state machine invokes services with privileged role
4. Lambda Code Modification (2 methods)
The principal can modify existing Lambda function code to inject commands.
lambda:UpdateFunctionCode- replace function code directlylambda:UpdateFunctionConfiguration+ layers - inject via Lambda layer
5. Trust Policy Abuse (1 method)
The principal can modify role trust policies to allow itself to assume privileged roles.
iam:UpdateAssumeRolePolicy- rewrite the trust policy
6. Permission Boundary Bypass (4 methods)
The principal can remove or modify permission boundaries that restrict its effective permissions.
iam:DeleteRolePermissionsBoundary- remove boundary from an assumed roleiam:DeleteUserPermissionsBoundary- remove own boundaryiam:PutRolePermissionsBoundary- replace role boundary with a permissive oneiam:PutUserPermissionsBoundary- replace own boundary with a permissive one
7. Resource Policy Abuse (2 methods)
The principal can modify resource-based policies on Lambda functions or layers to invoke or hijack privileged code without modifying its source.
lambda:AddPermission- cross-account/cross-principal invocation of a privileged Lambdalambda:AddLayerVersionPermission- share a malicious Lambda layer used by privileged functions
8. Compute Hijack (7 methods)
The principal can take over existing compute that already holds a privileged role, without needing iam:PassRole. The role is already attached - the attacker simply runs code in that environment.
ssm:SendCommand- execute arbitrary commands on a managed EC2 instance, code inherits the instance rolessm:StartSession- interactive shell on a managed EC2 instance, shell inherits the instance roleec2-instance-connect:SendSSHPublicKey- push an SSH key (60s validity) to an EC2 instance, login = shell with instance rolecodebuild:UpdateProject+codebuild:StartBuild- hijack an existing build project's buildspec to run code with its existing roleapprunner:UpdateService- replace the running container image of an AppRunner service, retain the privileged roleglue:UpdateDevEndpoint- hijack an existing Glue dev endpoint to run code with its rolesagemaker:CreatePresignedNotebookInstanceUrl- generate a presigned URL for an existing notebook, gain access with its role
9. Lateral AssumeRole (4 methods)
The principal can become admin without ever modifying any policy - by assuming a role through trust relationships. cloud-audit builds a directed graph from every role's AssumeRolePolicyDocument and walks it from each non-admin principal toward admin roles.
AssumeRole:Direct- principal P hassts:AssumeRoleand a role R trusts P explicitly; R has admin permissions (1 hop)AssumeRole:Chain- multi-hop chain: P trusts A, A trusts B, B is admin (2-4 hops)AssumeRole:WildcardTrust- role withPrincipal: "*"orPrincipal: { AWS: "*" }trust policy - any AWS identity can assume itAssumeRole:CrossAccountRoot- role trusts an external account's root principal (arn:aws:iam::OTHER:root), giving any IAM identity in that account assume rights
Detection notes:
- Same-account root expansion: a role trusting
arn:aws:iam::SAME_ACCOUNT:rootis treated as reachable by any principal in the same account withsts:AssumeRole - Bare account IDs (e.g.,
"123456789012") are normalized toarn:aws:iam::123456789012:rootper AWS semantics - Conditions are flagged, not evaluated: if a trust policy contains a
Conditionblock (MFA, ExternalId, SourceArn), the finding includes a warning to verify its effectiveness manually - Service-linked roles (path starting with
/aws-service-role/) are excluded from the graph - Permission boundaries and SCPs are out of scope for v2.1.0
Attack Chain Integration
Escalation paths feed into three attack chains:
| Chain | Description |
|---|---|
| AC-34 | PassRole Escalation to Admin |
| AC-35 | Self-Escalation via IAM Policy Modification |
| AC-36 | External Escalation via OIDC + Privilege Escalation |
When an escalation path is detected, it is reported as check aws-iam-018 and also triggers the relevant attack chain if the prerequisite conditions are met.
CLI
cloud-audit scan # includes escalation detection
cloud-audit list-checks --id aws-iam-018 # show check details
Escalation findings include the principal ARN, the escalation method, and the target privilege level in the finding details.