aws-cognito-developer-auth-abuse
An IAM principal with cognito-identity:GetOpenIdTokenForDeveloperIdentity can synthesize a developer-authenticated token for any developerUserId in the pool and exchange it for the authenticated role's IAM credentials, bypassing user authentication entirely.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?principal) in [
HumanIdentity, MachineIdentity, Role, ServiceIdentity]
node_type(?pool) == ApplicationIdentity # Cognito Identity Pool
?principal has EFFECTIVE cognito-identity:GetOpenIdTokenForDeveloperIdentity on ?pool ARN
?pool.DeveloperProviderName is not null # developer-authenticated flow configured
?auth_role = GetIdentityPoolRoles(?pool).Roles.authenticated
emit
| source type | Identity |
|---|---|
| target type | Role |
| source | ?principal |
| target | ?auth_role |
| permissions | cognito-identity:GetOpenIdTokenForDeveloperIdentity cognito-identity:GetCredentialsForIdentity |
| conditions | iam_permission |
| state logic | ACTIVE when GetOpenIdTokenForDeveloperIdentity is effective (not blocked by SCP or permission boundary) AND the pool has DeveloperProviderName set. No trust condition gates this path — the developer-auth API is designed to issue tokens for arbitrary user IDs; any effective holder of this permission can impersonate any pool user. BLOCKED if an SCP denies GetOpenIdTokenForDeveloperIdentity or GetCredentialsForIdentity for the pool. |
Narrative
{principal.name} holds effective cognito-identity:GetOpenIdTokenForDeveloperIdentity on Identity Pool {pool.name} (developer-provider: {pool.DeveloperProviderName}). It can synthesize a developer-authenticated token for any pool user, then call GetCredentialsForIdentity to receive temporary IAM credentials for authenticated role {auth_role.name} - without knowing any user's password.
Raw rule rules/derived/aws/cognito.yaml
id: aws-cognito-developer-auth-abuse
emits: CanFederateAs
description: An IAM principal with cognito-identity:GetOpenIdTokenForDeveloperIdentity can synthesize
a developer-authenticated token for any developerUserId in the pool and exchange it for the authenticated
role's IAM credentials, bypassing user authentication entirely.
applies_to:
- aws
match:
- - principal: null
- HasPermission
- pool: null
where:
- node_type(?principal) in [HumanIdentity, MachineIdentity, Role, ServiceIdentity]
- 'node_type(?pool) == ApplicationIdentity # Cognito Identity Pool'
- ?principal has EFFECTIVE cognito-identity:GetOpenIdTokenForDeveloperIdentity on ?pool ARN
- '?pool.DeveloperProviderName is not null # developer-authenticated flow configured'
- ?auth_role = GetIdentityPoolRoles(?pool).Roles.authenticated
emit:
source_type: Identity
target_type: Role
source: ?principal
target: ?auth_role
permissions:
- cognito-identity:GetOpenIdTokenForDeveloperIdentity
- cognito-identity:GetCredentialsForIdentity
conditions:
- iam_permission
state_logic: "ACTIVE when GetOpenIdTokenForDeveloperIdentity is effective (not blocked by SCP or permission\
\ boundary) AND the pool has DeveloperProviderName set. No trust condition gates this path \u2014\
\ the developer-auth API is designed to issue tokens for arbitrary user IDs; any effective holder\
\ of this permission can impersonate any pool user. BLOCKED if an SCP denies GetOpenIdTokenForDeveloperIdentity\
\ or GetCredentialsForIdentity for the pool."
confidence: 0.9
derived_from:
- ?principal HasPermission cognito-identity:GetOpenIdTokenForDeveloperIdentity on ?pool
- ?pool.DeveloperProviderName != null (cognito-identity:DescribeIdentityPool)
- GetIdentityPoolRoles.Roles.authenticated (authenticated role)
false_positive_note: "Only emit when the pool ACTUALLY has DeveloperProviderName configured (DescribeIdentityPool\
\ field DeveloperProviderName is non-null). Without it, GetOpenIdTokenForDeveloperIdentity returns\
\ an error. Verify that the calling principal's effective permission covers the specific pool ARN\
\ (not just *). This path bypasses the end-user's authentication entirely \u2014 it is not mitigated\
\ by strong user passwords or MFA \u2014 so a broad IAM grant of this action is high severity regardless\
\ of other pool configuration."
narrative: "{principal.name} holds effective cognito-identity:GetOpenIdTokenForDeveloperIdentity on\
\ Identity Pool {pool.name} (developer-provider: {pool.DeveloperProviderName}). It can synthesize\
\ a developer-authenticated token for any pool user, then call GetCredentialsForIdentity to receive\
\ temporary IAM credentials for authenticated role {auth_role.name} \u2014 without knowing any user's\
\ password."