Unscoped iam:PassRole Grants Let Lambda Deploy Roles Escalate to Admin Access
A wildcard iam:PassRole grant lets an AWS Lambda deploy identity pass any role, including privileged ones, to a function it controls — a quiet path to full account escalation.
Operational summary
At a glance
- Symptom
- CloudTrail shows a deployment identity — one whose declared job is publishing AWS Lambda functions — performing actions well outside that scope, such as…
- Likely cause
- An unscoped iam:PassRole statement, combined with permission to create or update a compute resource such as a Lambda function, lets the deploy identity pass…
- Impact
- Any identity that can reach this combination of permissions can escalate to the privilege level of the most powerful role reachable through PassRole, up to full account administration.
- Verification signal
- Re-test the exact paths used during diagnosis and confirm they now fail closed rather than assuming the fix worked.Re-run aws iam simulate-principal-policy for iam:PassRole against the previously reachable…
- Safe correction
- Replace the wildcard grant with a statement naming the specific role ARNs the deploy identity is permitted to pass, and add an iam:PassedToService condition restricting the grant to…
- Rollback or recovery
- If the scoped policy blocks a legitimate deployment, restore the previous policy version rather than reintroducing the wildcard grant.Identify the prior version with aws iam list-policy-versions --policy-arn .Restore…
Symptom
CloudTrail shows a deployment identity — one whose declared job is publishing AWS Lambda functions — performing actions well outside that scope, such as modifying S3 bucket policies, creating IAM users or reading secrets in other services. No policy directly attached to the deploy identity grants those permissions, so a review of its own attached policies finds nothing wrong.
The identity’s IAM policy still looks minimal and reasonable on paper: permission to manage Lambda functions, plus a broad iam:PassRole statement that the team added months earlier so deployments would not keep failing on role-assignment errors.
False Assumption
The review treats the wildcard iam:PassRole statement, scoped as Resource: "*", as low risk because it reasons that PassRole only lets the identity hand an existing role to a resource — it does not itself grant the permissions contained in that role. Since no broad managed policy such as AdministratorAccess is attached directly to the deploy identity, the wildcard grant is waved through as a convenience fix rather than a privilege boundary.
Root Cause
An unscoped iam:PassRole statement, combined with permission to create or update a compute resource such as a Lambda function, lets the deploy identity pass any role in the account — including roles with far greater privilege than the deploy identity itself — to that resource. Once the function runs under the passed role, code invoked through it executes with that role’s permissions, not the deploy identity’s own permissions. The escalation path never touches the deploy identity’s attached policy, so a policy review that only inspects the suspect identity’s own statements will not surface it.
Impact
Any identity that can reach this combination of permissions can escalate to the privilege level of the most powerful role reachable through PassRole, up to full account administration. Because the escalation happens through resource creation rather than a policy change, it produces CloudTrail events that look like ordinary deployment activity unless the reviewer specifically correlates PassRole calls against the role ARNs they target.
Diagnosis
Confirm the exposure before changing anything.
- Export the account’s IAM policy set with
aws iam get-account-authorization-detailsand search foriam:PassRolestatements usingResource: "*"or omitting aniam:PassedToServicecondition. - Use
aws iam simulate-principal-policyto test, against the ARN of a specific highly privileged role, whether the deploy identity is currently permitted to pass it. - Cross-reference CloudTrail
PassRoleevents issued by the deploy identity againstCreateFunction,UpdateFunctionConfigurationorRunInstancesevents targeting role ARNs outside the identity’s intended scope.
Correction
Replace the wildcard grant with a statement naming the specific role ARNs the deploy identity is permitted to pass, and add an iam:PassedToService condition restricting the grant to the intended service.
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::ACCOUNT_ID:role/lambda-deploy-execution-role",
"Condition": {
"StringEquals": { "iam:PassedToService": "lambda.amazonaws.com" }
}
}
Apply the scoped statement as a new managed-policy version rather than editing the existing version in place, so the previous version remains available if a legitimate deployment breaks.
Validation
Re-test the exact paths used during diagnosis and confirm they now fail closed rather than assuming the fix worked.
- Re-run
aws iam simulate-principal-policyforiam:PassRoleagainst the previously reachable privileged role ARN and confirm the result changes from allowed to denied. - In an isolated or non-production account, attempt to create a Lambda function passing the previously reachable role and confirm the call fails with
AccessDeniedreferencingiam:PassRole. - Review CloudTrail for the deploy role over the following 24 hours and confirm no
PassRoleevents target role ARNs outside the new allow-list.
Rollback
If the scoped policy blocks a legitimate deployment, restore the previous policy version rather than reintroducing the wildcard grant.
- Identify the prior version with
aws iam list-policy-versions --policy-arn <deploy-policy-arn>. - Restore it with
aws iam set-default-policy-version-id --policy-arn <deploy-policy-arn> --version-id <previous-version-id>. - Add the missing legitimate role ARN to the scoped allow-list and re-apply the fix rather than leaving the wildcard restored.
Prevention
Treat every iam:PassRole grant as carrying the risk of the most privileged role it can reach, and scope it during policy review rather than inspecting only the identity’s own attached permissions. Pair scoped PassRole statements with a permission boundary on deploy roles and a periodic export via get-account-authorization-details so wildcard grants introduced as quick fixes are caught before the next incident rather than after it. AWS’s Well-Architected Security Pillar documents design principles and operational practices for protecting AWS workloads, including applying least-privilege access as a routine review discipline rather than a one-off remediation; incorporate PassRole scoping checks into that recurring review cycle.
Apply the safer control
Before you change production
Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.
Fix commands and configuration
iam:PassRoleResource: "*"PassRoleVerify, roll back or escalate
Verify
Re-test the exact paths used during diagnosis and confirm they now fail closed rather than assuming the fix worked.Re-run aws iam simulate-principal-policy for iam:PassRole against the previously reachable privileged role ARN and confirm the result changes from allowed to denied.In…
Rollback
If the scoped policy blocks a legitimate deployment, restore the previous policy version rather than reintroducing the wildcard grant.Identify the prior version with aws iam list-policy-versions --policy-arn <deploy-policy-arn>.Restore it with aws iam set-default-policy-version-id --policy-arn <deploy-policy-arn> --version-id <previous-version-id>.Add the missing legitimate…
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.