Glossary

    Privilege Escalation

    Identity & Access

    Privilege Escalation in AWS occurs when a principal obtains permissions beyond what was intended. This typically happens through IAM misconfigurations that allow a user to modify their own permissions or create new high-privilege identities.

    Common AWS Privilege Escalation Paths

    • iam:CreatePolicy + iam:AttachUserPolicy: create an admin policy and attach it to yourself
    • iam:PassRole + lambda:CreateFunction: pass a high-privilege role to a new Lambda function you control
    • iam:CreateLoginProfile: create console access for another user, then log in as them
    • iam:UpdateAssumeRolePolicy: modify a role's trust policy to allow yourself to assume it
    • sts:AssumeRole on overly permissive roles: assume a role with broader permissions
    • iam:CreatePolicyVersion with --set-as-default: rewrite an existing attached policy instead of attaching a new one
    • iam:CreateAccessKey on another user: mint long-term credentials for a more privileged identity

    Prevention

    • Never grant iam:*, scope IAM permissions carefully
    • Use permission boundaries to cap maximum permissions
    • Restrict iam:PassRole to specific role ARNs
    • Monitor for privilege escalation with GuardDuty and CloudTrail

    How It Goes Wrong in Practice

    The single most common enabler is an unscoped iam:PassRole. A team gives its CI/CD pipeline or its developers permission to deploy compute, so the policy includes lambda:CreateFunction, ec2:RunInstances, or ecs:RegisterTaskDefinition, plus iam:PassRole on Resource: "*" because nobody knew which role ARNs to list. That combination is a full escalation path. The holder creates a Lambda function, passes the account's most privileged existing role to it (a Terraform execution role or a break-glass admin role), and invokes the function with code that calls whatever API they want. The pipeline identity itself never had admin permissions, yet it can execute as admin.

    The same pattern shows up with EC2: pass an admin instance profile to an instance you launch, then read credentials from the instance metadata service. And with Glue, SageMaker, CloudFormation, and Data Pipeline, each of which accepts a role and runs code under it. The fix is always the same: iam:PassRole must name the exact role ARNs the identity is allowed to pass, and ideally use the iam:PassedToService condition key so a role meant for Lambda cannot be passed to EC2.

    One detail that catches people during investigations: PassRole is a permission, not an API call, so there is no CloudTrail event named PassRole. To see which roles were passed to which services, you have to review the log entry for the action that created or modified the resource, for example the CreateFunction event for a Lambda function.

    A second frequent path is policy version manipulation. An identity that holds iam:CreatePolicyVersion on a policy already attached to it can publish a new default version containing "Action": "*". No attach action is needed, so policies that only deny iam:AttachUserPolicy miss it entirely.

    Testing a Principal for Escalation Paths

    The IAM policy simulator answers "could this identity do X" without actually calling the API:

    aws iam simulate-principal-policy --policy-source-arn arn:aws:iam::123456789012:role/ci-deploy-role --action-names iam:PassRole iam:CreatePolicyVersion iam:AttachRolePolicy lambda:CreateFunction

    Both --policy-source-arn (the user, group, or role to evaluate) and --action-names (one or more actions in service:Action form) are required. The output returns an EvalDecision per action with one of three values: allowed, explicitDeny, or implicitDeny. Anything that comes back allowed for a role-passing or IAM-writing action deserves a closer look. Run this against your CI/CD roles and developer roles as a regular check, not just once.

    Frequently Asked Questions

    Does a permission boundary stop privilege escalation?

    It caps what the escalated identity can end up with, which is genuinely useful, but only if the boundary itself is protected. If the identity can call iam:DeleteRolePermissionsBoundary or modify the boundary policy, the ceiling is removable. Deny those actions explicitly, and pair boundaries with an SCP so the guardrail survives account-level mistakes.

    Will GuardDuty detect privilege escalation?

    GuardDuty produces findings for suspicious IAM behavior such as anomalous API calls and credentials used from unusual locations, and it can flag activity consistent with escalation attempts. It is a detection layer, not a prevention layer, and it will not catch an escalation that looks like normal deployment activity. Prevention through scoped iam:PassRole and boundaries matters more.

    Which permissions should I treat as effectively administrative?

    Any permission that lets an identity create or modify identities and policies, or pass a role to a compute service. That includes iam:CreatePolicyVersion, iam:AttachUserPolicy, iam:AttachRolePolicy, iam:PutUserPolicy, iam:PutRolePolicy, iam:UpdateAssumeRolePolicy, iam:CreateAccessKey, iam:CreateLoginProfile, iam:UpdateLoginProfile, and unscoped iam:PassRole. Treat granting any of these with the same review you would give AdministratorAccess.

    Related AWS Services

    Toc Consulting: AWS Security & Cloud Architecture

    Securing your AWS estate?

    Our team helps engineering teams secure and architect AWS the right way: assessment in week one, a prioritized action plan in week two.