Free plan Signups are open now. The full audytx engine — Terraform and CloudFormation — is live. The Free plan is 100 scans a month and stays free — paid tiers arrive Nov 01, 2026 from $20/month for unlimited repositories. Try it on your own code.
AWS IAM security · Terraform + CloudFormation · attack-path reasoning

AWS IAM privilege escalation detection in Terraform

Many IaC checks look at one IAM resource at a time. audytx also builds an effective-permission graph across your Terraform, resolves who can assume each role, and traces iam:PassRole grants and AssumeRole role chaining to find privilege-escalation paths by reachability. The engine is deterministic and hand-written — identical input, identical findings, no model in the loop. On the BishopFox iam-vulnerable corpus it detected all 31 documented paths in our last measured run (engine 1.18.276, 2026-08-07).

iam:PassRole chains AssumeRole role chaining trust-policy analysis wildcard matching effective-permission graph end-to-end attack paths
31
iam-vulnerable IAM escalation paths — every one detected in the last measured run
100%
recall on the BishopFox iam-vulnerable corpus, measured 2026-08-07
Same
Deterministic: identical input, identical findings
The problem

What IAM privilege escalation is in Terraform

A principal with limited permissions grants itself more by chaining API calls: attach a policy, assume another role, or pass a privileged role to a service. In Terraform the chain is visible across the configuration — a policy grants iam:PassRole, a function references that role, a trust policy lets the principal assume it — so detecting it means reading all three together.

Checking one resource at a time

Flags each resource against a checklist: "this policy has iam:PassRole." Without the chain it faces a choice — stay quiet and miss the path, or flag every occurrence and add noise to the review.

audytx: graph reachability

  • Matches wildcard actions (iam:*, lambda:*) against the permissions they cover
  • Runs trust policy analysis: who can assume each role?
  • Walks AssumeRole and PassRole chains across the resource graph
  • Reports the chain where it can be traced: source principal → escalation vector → elevated permissions
Coverage

The 31 iam-vulnerable paths, detected

The BishopFox iam-vulnerable corpus documents 31 AWS IAM privilege-escalation paths, one Terraform file per path. audytx detected every one in the last measured run (engine 1.18.276, 2026-08-07) — grouped here by the upstream categories. For the actions each policy grants, see the path table.

IAM permissions on other users PassRole to service permissions on policies escalation using AWS services updating an AssumeRole policy
IAM Permissions on Other Users
IAM-CreateAccessKey
iam:CreateAccessKey
IAM Permissions on Other Users
IAM-CreateLoginProfile
iam:CreateLoginProfile
IAM Permissions on Other Users
IAM-UpdateLoginProfile
iam:UpdateLoginProfile
PassRole to Service
CloudFormation-PassExistingRoleToCloudFormation
iam:PassRole, cloudformation:CreateStack
PassRole to Service
CodeBuild-CreateProjectPassRole
iam:PassRole, codebuild:CreateProject, codebuild:StartBuild, codebuild:StartBuildBatch
PassRole to Service
DataPipeline-PassExistingRoleToNewDataPipeline
iam:PassRole, datapipeline:CreatePipeline, datapipeline:PutPipelineDefinition, datapipeline:ActivatePipeline
PassRole to Service
EC2-CreateInstanceWithExistingProfile
iam:PassRole, ec2:RunInstances
PassRole to Service
Glue-PassExistingRoleToNewGlueDevEndpoint
iam:PassRole, glue:CreateDevEndpoint
PassRole to Service
Lambda-PassExistingRoleToNewLambdaThenInvoke
iam:PassRole, lambda:CreateFunction, lambda:InvokeFunction
PassRole to Service
Lambda-PassRoleToNewLambdaThenTrigger
iam:PassRole, lambda:CreateFunction, lambda:CreateEventSourceMapping
PassRole to Service
SageMaker-CreateNotebookPassRole
iam:PassRole, sagemaker:CreateNotebookInstance
PassRole to Service
SageMaker-CreateTrainingJobPassRole
iam:PassRole, sagemaker:CreateTrainingJob
PassRole to Service
SageMaker-CreateProcessingJobPassRole
iam:PassRole, sagemaker:CreateProcessingJob
Permissions on Policies
IAM-AddUserToGroup
iam:AddUserToGroup
Permissions on Policies
IAM-AttachGroupPolicy
iam:AttachGroupPolicy
Permissions on Policies
IAM-AttachRolePolicy
iam:AttachRolePolicy
Permissions on Policies
IAM-AttachUserPolicy
iam:AttachUserPolicy
Permissions on Policies
IAM-CreateNewPolicyVersion
iam:CreatePolicyVersion
Permissions on Policies
IAM-PutGroupPolicy
iam:PutGroupPolicy
Permissions on Policies
IAM-PutRolePolicy
iam:PutRolePolicy
Permissions on Policies
IAM-PutUserPolicy
iam:PutUserPolicy
Permissions on Policies
IAM-SetExistingDefaultPolicyVersion
iam:SetDefaultPolicyVersion
Privilege Escalation using AWS Services
EC2InstanceConnect-SendSSHPublicKey
ec2-instance-connect:SendSSHPublicKey
Privilege Escalation using AWS Services
CloudFormation-UpdateStack
cloudformation:UpdateStack
Privilege Escalation using AWS Services
Glue-UpdateExistingGlueDevEndpoint
glue:UpdateDevEndpoint
Privilege Escalation using AWS Services
Lambda-EditExistingLambdaFunctionWithRole
lambda:UpdateFunctionCode
Privilege Escalation using AWS Services
SageMakerCreatePresignedNotebookURL
sagemaker:CreatePresignedNotebookInstanceUrl
Privilege Escalation using AWS Services
SSM-SendCommand
ssm:SendCommand
Privilege Escalation using AWS Services
SSM-StartSession
ssm:StartSession
Privilege Escalation using AWS Services
STS-AssumeRole
sts:AssumeRole along a role chain that ends in a full-access policy
Updating an AssumeRole Policy
IAM-UpdatingAssumeRolePolicy
iam:UpdateAssumeRolePolicy, sts:AssumeRole
Measured

Our result on iam-vulnerable

All 31 documented paths detected in the last measured run. The result is dated and is not re-measured on every release.

31 / 31
paths detected
BishopFox iam-vulnerable, pinned commit
100%
recall
engine 1.18.276, 2026-08-07

Corpus: BishopFox iam-vulnerable · 31 documented paths · one Terraform file per path.

Free plan

Start free

Install audytx on one repo. The next pull request that touches IAM gets the full attack-path analysis — iam:PassRole chains, role chaining, trust-policy and wildcard reasoning — right in the review comment.

Worked example

A worked example: PassRole in Terraform

Two Terraform files and the findings audytx reported for them.

The setup: A developer role (trusted by EC2) whose policy allows iam:PassRole and lambda:InvokeFunction on all resources, a Lambda function, and an admin role (trusted by Lambda) with the AWS-managed AdministratorAccess policy attached.
# iam_role_developer.tf
resource "aws_iam_role" "developer" {
  name = "developer-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Action    = "sts:AssumeRole"
      Principal = { Service = "ec2.amazonaws.com" }
    }]
  })
}

resource "aws_iam_role_policy" "developer_policy" {
  role = aws_iam_role.developer.id
  policy = jsonencode({
    Statement = [{
      Effect   = "Allow"
      Action   = ["lambda:InvokeFunction", "iam:PassRole"]
      Resource = "*"
    }]
  })
}
# lambda.tf
resource "aws_lambda_function" "updater" {
  function_name = "config-updater"
  role          = aws_iam_role.admin.arn  # ← receives the passed role
}

resource "aws_iam_role" "admin" {
  name = "admin-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Action    = "sts:AssumeRole"
      Principal = { Service = "lambda.amazonaws.com" }
    }]
  })
}

resource "aws_iam_role_policy_attachment" "admin_policy" {
  role       = aws_iam_role.admin.name
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
audytx findings (the Critical and High findings from a scan of these two files, engine 1.19.579):
  1. [HIGH] AWS_IAM_020 · iam_role_developer.tf · developer_policy
    IAM policy developer_policy: enables privilege escalation — pass any role to a compute service — granted on an unconstrained resource (Resource: "*") with no Condition. Any principal holding this policy can escalate to broader or administrator privileges.
  2. [HIGH] AWS_IAM_021 · iam_role_developer.tf · aws_iam_role.developer
    Toxic combination on role developer: it is assumable by a compute service (EC2 / ECS / Lambda), AND its attached policies grant pass any role to a compute service. An attacker who compromises that workload (SSRF, RCE, dependency takeover) can steal the instance/task role credentials and obtain those permissions. Neither the trust policy nor the permission policy is flagged in isolation — the risk is the path between them.
  3. [HIGH] AWS_IAM_021 · lambda.tf · aws_iam_role.admin
    Toxic combination on role admin: it is assumable by a compute service (EC2 / ECS / Lambda), AND its attached policies grant full administrator wildcard (Action: "*"). An attacker who compromises that workload (SSRF, RCE, dependency takeover) can steal the instance/task role credentials and obtain those permissions. Neither the trust policy nor the permission policy is flagged in isolation — the risk is the path between them.
  4. [CRITICAL] AWS_OPS_036 · lambda.tf · aws_iam_role_policy_attachment.admin_policy
    admin_policy: a full-privilege AWS-managed policy (AdministratorAccess or IAMFullAccess) is attached. AdministratorAccess grants unrestricted access to every service; IAMFullAccess grants full IAM control, which can be used to attach AdministratorAccess to any principal and escalate to full account control.

The scan also returned lower-severity findings on these files, which are not shown. The two AWS_IAM_021 findings are the cross-resource ones: each combines a role's trust policy with the permissions attached to it.

What it checks

IAM security checks in audytx

Direct misconfigurations and cross-resource attack paths. Data the configuration doesn't supply is reported as Incomplete, not assumed.

IAM privilege-escalation checks

Reachability across roles, policies, trust relationships, and services. Finds iam:PassRole chains, AssumeRole role chaining, and service-linked escalation vectors.

Effective-permission matching

Wildcards (iam:*, *) are matched against the actions they cover. A principal with iam:* gets the same treatment as one with every individual IAM action listed.

Trust policy analysis

Who can assume each role? audytx reads each role's trust policy — a cross-account trust to * is treated differently from a same-account service trust.

Context suppression

Findings that other resources show to be harmless are held back, with the reason shown.

See the full IAM check inventory on the features page.

FAQ

IAM privilege escalation: common questions

What is IAM privilege escalation in Terraform?

IAM privilege escalation happens when a principal with limited permissions grants itself more by chaining API calls — attaching a policy, assuming another role, or passing a privileged role to a service like Lambda or EC2. In Terraform these chains are visible across the configuration if you read the resources together.

Can Terraform scanners detect privilege escalation?

Checks that look at one resource at a time have to either stay quiet and miss the path, or flag every occurrence and add noise to the review. audytx builds an effective-permission graph and traces reachability across roles, policies, and trust relationships to follow the path instead.

How does audytx detect iam:PassRole chains?

audytx builds an effective-permission graph across the whole Terraform configuration, matches wildcard actions against the permissions they cover, and resolves trust policies to learn who can assume each role. It then follows PassRole and AssumeRole chains across the resource graph and reports what it can trace from source principal to elevated permissions.

See IAM findings on your next PR

Install audytx on one repo. The next PR that touches IAM gets the full attack-path analysis in the review comment: iam:PassRole chains, role chaining, trust policy analysis, wildcard matching.

Install audytx free →

Or use the MCP server: claude mcp add --transport http audytx https://audytx.com/mcp --header "X-Client-ID: YOUR_CLIENT_ID"