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.

derived aws emits CanFederateAs

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} HasPermission {'pool': None}

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 typeIdentity
target typeRole
source?principal
target?auth_role
permissionscognito-identity:GetOpenIdTokenForDeveloperIdentity cognito-identity:GetCredentialsForIdentity
conditionsiam_permission
state logicACTIVE 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."
move · open · esc close