📋 What Is It?
Over-Privileged Function Permissions & Roles occurs when a function is granted far more IAM permission than it needs. Instead of being scoped to the one table it reads or the one bucket it writes, the function carries wildcard actions, wildcard resources, broad *FullAccess managed policies, or a single shared role reused across the whole app. The permission the function holds is much larger than the permission it uses. In serverless there is no host or network to fall back on - the IAM policy is the security perimeter. Over-privilege is rarely the way in; it is the multiplier that turns a contained bug into an account-wide breach.
⚠️ Common Exploits
- Shared Role: one broad provider-level role inherited by every function
- Wildcard Actions:
"*",s3:*,dynamodb:*- includes delete and full scans - Wildcard Resource:
Resource: "*"turns a narrow action account-wide - Broad Managed Policies:
*FullAccessattached "to unblock the build" - iam:PassRole: unscoped - borrow a more privileged role
- iam:* Write: attach admin policy, self-escalate to account admin
- Permission Drift: grants added per feature, never removed
🔴 Attack Flow
↓
2. Harvest the role's credentials from
AWS_* env vars↓
3. Enumerate what the role can do (List*, Get*, sts:GetCallerIdentity)
↓
4. Abuse wildcards: read every bucket/table, invoke every function
↓
5. IMPACT: PassRole / iam:* escalate to account-wide admin!
❌ Vulnerable Code
✅ Secure Code
✓ Prevention Checklist
- Give every function its own least-privilege role
- Never attach a broad shared provider-level role
- Replace every
*with explicit actions and ARNs - Never use
service:*orResource: "*"for data services - Avoid
*FullAccessmanaged policies - Tighten with conditions (SourceArn, LeadingKeys, encryption)
- Scope
iam:PassRoleto specific role ARNs + service condition - Never grant
iam:*or policy-editing actions to a function - Compare granted vs. used and remove the surplus
- Apply permission boundaries as a hard ceiling
- Separate roles by trust level and data sensitivity
- Enforce least privilege in IaC and re-check every deploy
🔍 Detection & Tools
Least-Privilege Analysis:
Monitoring & Pivots:
How to Test:
- Inventory roles: is each function's role unique?
- Grep IaC for
Action: "*",service:*,Resource: "*" - Flag any
*FullAccessmanaged policy on execution roles - Check for unscoped
iam:PassRoleandiam:* - Run Access Analyzer to compare granted vs. used
- Simulate: from a function's role, what can you reach?
🌍 Real-World
These are documented incident classes - recurring patterns, not specific CVEs.
- One compromised function, whole-account reach: an internet-facing function with
s3:*anddynamodb:*onResource: "*"is exploited; because the role is account-wide, the attacker exfiltrates buckets and tables unrelated to the function. - Privilege escalation via iam:PassRole: a limited role holds unscoped
PassRoleplus the ability to create compute; the attacker attaches a far more privileged existing role and operates as it. - *FullAccess as the default: a managed full-access policy attached in development and never tightened, exposing an entire service to any one weak function.
- Shared-role blast radius: many functions share one role, so compromising the least-defended
healthCheckyields the same power as every other function. - Denial-of-wallet via created compute: permission to spin up instances or functions abused for cryptomining on the victim's bill.
📌 Quick Tips
- DO NOT share one broad role across functions
- DO NOT use
Action: "*"orResource: "*" - DO NOT grant unscoped
iam:PassRoleoriam:* - DO give each function its own least-privilege role
- DO pin specific actions and resource ARNs
- DO cap roles with permission boundaries
- DO compare granted vs. used continuously
📜 Compliance
Related Standards:
- OWASP Serverless Top 10 - SAS-4
- CWE-250 Execution with Unnecessary Privileges
- CWE-269 Improper Privilege Management
- PCI-DSS Requirement 7 - Least Privilege
- SOC 2 / ISO 27001 Access Control