返回资讯中心
外部精选
软件工程
#开发者实时流

Why IAM:PassRole is a common privilege escalation path in AWS

When we audit AWS accounts, the most interesting findings are rarely the obvious ones like a public S3 bucket or an access key committed to Git. The findings that change the risk profile of a whole account are usually h…

Hacker News 最新lkanwoqwp2026/10/18 · 19 天前15 分钟阅读

以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。

When we audit AWS accounts, the most interesting findings are rarely the obvious ones like a public S3 bucket or an access key committed to Git. The findings that change the risk profile of a whole account are usually hidden in one line of an IAM policy. One of the lines that is catching an eye is "Action": "iam:PassRole", "Resource": "*".

iam:PassRole looks harmless. It does not create anything, it does not read data, and it doesn’t even appear as a separate event in CloudTrail, but it can turn a “limited” developer or CI/CD role into an account administrator.

In this article I explain what iam:PassRole actually does, why it is so often part of privilege escalation paths in AWS, and how to restrict it with least-privilege policies, conditions, and organization-level guardrails.

To configure many services, you must pass an IAM role to the service. This allows the service to assume the role later and perform actions on your behalf. A Lambda function writes to DynamoDB, an EC2 instance reads from S3, an ECS task pulls secrets from Secrets Manager. They do it by assuming an IAM role that you attach when you create or update the resource:

To attach a role to such a resource, the actor needs permission to call the service API (for example lambda:CreateFunction) and permission iam:PassRole on that role. PassRole is AWS’s answer to the question: “Is this principal allowed to give this role to a service?”

Without iam:PassRole, the actor can create the resource but cannot attach a role to it. This is a common privilege escalation path in AWS, because iam:PassRole is often part of the permissions required to create resources.

For example with having permission to "lambda:*" but without iam:PassRole, the actor can create a Lambda function but cannot attach a role to it so in web UI you will get: "User: arn:aws:iam::123456789:user1 is not authorized to perform: iam:PassRole on resource: arn:aws:iam::123456789:role/service-role/test-role-xxx with an explicit deny ..."

A minimal working example: a developer who can create Lambda functions using only dedicated execution roles.

{ "Version": "2012-10-17", "Statement": [ { "Sid": "CreateFunctions", "Effect": "Allow", "Action": ["lambda:CreateFunction", "lambda:UpdateFunctionConfiguration"], "Resource": "arn:aws:lambda:eu-central-1:123456789:function:app-" }, { "Sid": "PassOnlyLambdaExecutionRoles", "Effect": "Allow", "Action": "iam:PassRole", "Resource": "arn:aws:iam::123456789:role/lambda-exec-app-", "Condition": { "StringEquals": { "iam:PassedToService": "lambda.amazonaws.com" } } } ] }

What’s critical here is the Resource (which roles can be passed) and the iam:PassedToService condition.

Passing a role involves two independent checks:

Only when both are satisfied, the service assumes the role and receives temporary credentials.

This is the key difference compared to sts:AssumeRole:

PassRole is not an API action. It’s only permission so it is not logged as PassRole event in CloudTrail. It can be seen in parameters of API calls like CreateFunction or RunInstances.

The service that receives the role runs code that the caller controls. A Lambda function runs the code you upload. For example Lambda function runs code that you provide using its execution role.

So the effective question in an audit is not “what can this user do?” but:

What can this user do plus everything that any role they can pass can do - through every service they can configure?

If a CI/CD role has limited permissions but can pass an administrator role to a service it can configure, then the CI/CD role is, in practice, an administrator. No policy says so explicitly, and a quick look at its attached policies won’t reveal it. This is why PassRole-based paths are a category in AWS IAM privilege escalation.

These are the patterns we see most often during AWS security audits:

Grant PassRole only on the roles that a given workload really needs. A naming convention helps - for example lambda-exec-<app>-, ecs-task-<app>-. Never reuse a workload role naming pattern for administrative roles.

iam:PassedToService limits which service can receive the role.

"Condition": { "StringEquals": { "iam:PassedToService": "ecs-tasks.amazonaws.com" } }

  1. Keep Trust Policies Narrow

A role should trust one service principal whenever possible. For cross-service or cross-account scenarios, use conditions such as aws:SourceArn and aws:SourceAccount to prevent the confused deputy problem.

In AWS Organizations, a Service Control Policy can deny passing privileged roles to everyone except for example dedicated platform automation role:

{ "Version": "2012-10-17", "Statement": [ { "Sid": "DenyPassingPrivilegedRoles", "Effect": "Deny", "Action": "iam:PassRole", "Resource": "arn:aws:iam::123456789:role/admin-*", "Condition": { "ArnNotLike": { "aws:PrincipalArn": "arn:aws:iam::123456789:role/platform-automation" } } } ] }

This same approach can be used to secure other cases.

For accounts where developers can create their own roles, combine this with a permissions boundary: new roles created by developers must carry a boundary, so even if they pass such a role, it can never exceed the boundary.

The pipeline, Terraform user that deploys a Lambda function needs PassRole on its execution role, but it does not need the permissions of that execution role. Make sure roles of automations can pass only the workload roles of the application they deploy.

The risk comes from combinations of permissions. The best detection methods look at the whole graph of principals, roles, and services, not at single statements:

iam:PassRole is a permission that doesn’t do anything by itself, is not visible in CloudTrail, which is exactly why it is so often granted too broadly. Treat every PassRole statement as a potential escalation path: scope it to specific role ARNs, always add iam:PassedToService, keep trust policies narrow, and secure everything with SCPs and permission boundaries.

New posts, good links and things that work.

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →