Back to Checks
Custom IAM policy does not allow STS role assumption on wildcard resources
iam_no_custom_policy_permissive_role_assumption
Service: iamSeverity: high
OfficialBuilt-inVerified
Categories:identity-access
Resource Type:AwsIamPolicy
Custom IAM policies with Allow statements that grant sts:AssumeRole (or sts:*/*) to a wildcard Resource.
Risk
Broad AssumeRole rights let principals obtain temporary credentials for many roles, enabling privilege escalation, lateral movement, and cross-account access where trusts allow. This jeopardizes confidentiality and integrity of data and the control plane.
Run this check with Prowler
Run in Prowler CloudRun
prowler aws --checks iam_no_custom_policy_permissive_role_assumptionRecommendation
Apply least privilege to sts:AssumeRole:
- Scope
Resourceto exact role ARNs - Require MFA and, for third parties,
ExternalId - Enforce permissions boundaries and SCPs to block wildcards
- Regularly remove unused role-assumption rights and separate duties
Remediation
CLI
aws iam create-policy-version --policy-arn <example_policy_arn> --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"sts:AssumeRole","Resource":"arn:aws:iam::<example_account_id>:role/<example_resource_name>"}]}' --set-as-defaultTerraform
# Terraform: Replace wildcard resource with a specific role ARN
resource "aws_iam_policy" "<example_resource_name>" {
name = "<example_resource_name>"
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:AssumeRole"
Resource = "arn:aws:iam::<example_account_id>:role/<example_resource_name>" // CRITICAL: restrict to a specific role ARN to remove wildcard
}]
})
}NativeIaC
# CloudFormation: Replace wildcard resource with a specific role ARN
Resources:
<example_resource_name>:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: sts:AssumeRole
Resource: arn:aws:iam::<example_account_id>:role/<example_resource_name> # CRITICAL: restrict to a specific role ARN to remove wildcardOther
1Open the AWS Console and go to IAM > Policies
2Select the custom policy that FAILED and click Edit policy (JSON)
3Find any statement with Effect: Allow and Action including sts:AssumeRole (or sts:* or *) where Resource is "*"
4Change Resource to the specific role ARN(s), e.g.: arn:aws:iam::<example_account_id>:role/<example_resource_name>
5Save changes to create the new default version
Check Code
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.iam.iam_client import iam_client
class iam_no_custom_policy_permissive_role_assumption(Check):
def execute(self) -> Check_Report_AWS:
findings = []
def resource_has_wildcard(resource):
if isinstance(resource, str):
return "*" in resource
if isinstance(resource, list):
return any("*" in r for r in resource)
return False
for policy in iam_client.policies.values():
# Check only custom policies
if policy.type == "Custom":
if not policy.attached and not iam_client.provider.scan_unused_services:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=policy)
report.region = iam_client.region
report.status = "PASS"
report.status_extended = f"Custom Policy {policy.name} does not allow permissive STS Role assumption."
if policy.document:
if not isinstance(policy.document["Statement"], list):
policy_statements = [policy.document["Statement"]]
else:
policy_statements = policy.document["Statement"]
for statement in policy_statements:
if (
statement.get("Effect") == "Allow"
and "Action" in statement
and "Resource" in statement
and resource_has_wildcard(statement["Resource"])
):
actions = (
statement["Action"]
if isinstance(statement["Action"], list)
else [statement["Action"]]
)
for action in actions:
if action in ["sts:AssumeRole", "sts:*", "*"]:
report.status = "FAIL"
report.status_extended = f"Custom Policy {policy.name} allows permissive STS Role assumption."
break
if report.status == "FAIL":
break
findings.append(report)
return findings