AWS IAM privilege escalation detection in Terraform
Most IaC scanners check IAM resources in isolation — single-resource pattern
matching against one policy file at a time. audytx 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 verdict comes from that graph:
deterministic and hand-written — identical input, identical findings, no model
in the loop. On the BishopFox iam-vulnerable corpus that means full
recall on the 31 documented paths at the highest precision of any tool with
full recall.
iam:PassRole chains
AssumeRole role chaining
trust-policy analysis
wildcard expansion
effective-permission graph
end-to-end attack paths
iam-vulnerable corpusWhat 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.
Pattern-matching scanner
Flags each resource against a checklist: "this policy has iam:PassRole." Without the chain it faces a false choice — stay quiet and miss the path (KICS: 3% recall, Trivy: 0%), or flag every occurrence and drown the review (Checkov: 238 false positives to reach the same 31 paths).
audytx: graph reachability
- Expands wildcard actions (
iam:*,lambda:*) to concrete permissions - Runs trust policy analysis: who can assume each role?
- Walks
AssumeRoleandPassRolechains across the resource graph - Flags the full chain: source principal → escalation vector → elevated permissions
All 31 documented IAM privilege-escalation paths, detected
The BishopFox iam-vulnerable corpus documents 31 AWS IAM privilege-escalation paths, one Terraform file per path. audytx detects every one — grouped here by escalation vector. For a path-by-path reference — the exact IAM actions each one needs, cited to AWS, with a mitigation for each — see the full privilege-escalation guide.
Benchmark: audytx vs Checkov, Trivy, KICS on iam-vulnerable
Same corpus, same 100% recall — half the alert volume of Checkov and twice the IAM precision.
| Tool | HIGH findings | TP (paths) | FP | Precision | Recall |
|---|---|---|---|---|---|
| audytx | 135 | 31 | 104 | 23% | 100% |
| Checkov | 269 | 31 | 238 | 12% | 100% |
| KICS | 9 | 1 | 8 | 11% | 3% |
| Trivy | 7 | 0 | 7 | 0% | 0% |
Corpus: BishopFox iam-vulnerable · 31 documented paths · one Terraform file per path. Full methodology and raw data: audytx benchmark page.
Start free during the open beta
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.
A worked example: PassRole privilege escalation in Terraform
How three Terraform files create an IAM privilege-escalation path that single-resource pattern matching can't prove.
iam:PassRole on the admin role. Single-resource scanners either stay quiet or flag the bare iam:PassRole grant without proving where it leads. audytx reads the chain and reports the full path.
# iam_role_developer.tf
resource "aws_iam_role" "developer" {
name = "developer-role"
}
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"
}
resource "aws_iam_role_policy_attachment" "admin_policy" {
role = aws_iam_role.admin.name
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
[CRIT] ATTACK_PATH_SEARCH — aws_iam_role.developer has iam:PassRole on aws_iam_role.admin (AdministratorAccess). Principal can invoke aws_lambda_function.updater to execute arbitrary code with admin permissions. Privilege-escalation path: developer → PassRole → admin → AdministratorAccess.
A pattern matcher scanning only iam_role_policy sees iam:PassRole as a potential concern but can't confirm the target role is privileged without reading iam_role_policy_attachment. audytx resolves the full chain across all three resources.
IAM security checks in audytx
Direct misconfigurations and cross-resource attack paths. A verdict never rests on
a guessed value — data the configuration doesn't supply is reported as unverifiable
(Incomplete), not assumed.
ATTACK_PATH_SEARCH
Graph-reachability search across roles, policies, trust relationships, and services. Finds iam:PassRole chains, AssumeRole role chaining, and service-linked escalation vectors.
Effective-permission expansion
Wildcards (iam:*, *) are expanded to concrete actions before reasoning. 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 checks both the principal list and aws:PrincipalAccount conditions — a cross-account trust to * is treated differently from a same-account service trust.
Context suppression
Not every high-privilege role is a finding. An admin role used only by a known-safe service with a narrowly-scoped trust policy may be suppressed, with the reasoning shown in the PR comment.
See the full IAM check inventory on the features page and the raw benchmark data on the comparison page.
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?
Single-resource pattern matchers struggle. Without following the chain they either stay quiet and miss the path, or flag every occurrence and drown the review in false positives. audytx builds an effective-permission graph and traces reachability across roles, policies, and trust relationships to prove the full path instead.
How does audytx detect iam:PassRole chains?
audytx builds an effective-permission graph across the whole Terraform configuration, expands wildcard actions to concrete permissions, and resolves trust policies to learn who can assume each role. It then walks PassRole and AssumeRole chains across the resource graph, reporting the full path 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 expansion.
Install audytx free →Or use the MCP server: claude mcp add --transport http audytx https://audytx.com/mcp