AWS Cognito Misconfigurations Worth Real Bounty Money
Cognito shows up the moment a web app has a login form backed by AWS. There are two moving parts people conflate: a User Pool (the directory that issues JWTs) and an Identity Pool (the thing that hands out temporary AWS credentials). Most juicy findings live in the seam between them.
Grab the client config first
Cognito front ends leak their own settings. Dig through the JavaScript bundle for a region, a UserPoolId like us-east-1_AbC123, an AppClientId, and often an IdentityPoolId. These are not secrets by design, which is exactly why misconfigurations bite.
With a client ID you can talk to the Cognito API directly using the AWS CLI or boto3 against the public cognito-idp endpoint — no console access required.
Open self-registration
The first test is whether SignUp is open. Call it:
aws cognito-idp sign-up --client-id <id> \
--username tester+canary@example.com --password 'Sup3r!Passw0rd'
If registration succeeds on an app that supposedly gates access, you may have crossed a boundary the product assumed was closed. Pair it with an admin-only page to show impact — an account that shouldn't exist reaching a feature that should be paywalled or invite-only.
Watch for auto-verification and attribute self-assignment. If email_verified or a custom custom:role attribute is writable during sign-up or via UpdateUserAttributes, that's a privilege bug. I've seen apps trust custom:tenant from the token without ever checking the user could set it themselves.
Guest access and identity pool roles
Identity Pools can be configured to grant unauthenticated (guest) AWS credentials. Request them:
aws cognito-identity get-id --identity-pool-id <pool>
aws cognito-identity get-credentials-for-identity --identity-id <id>
Now you hold real, if temporary, AWS keys. The severity depends entirely on the IAM role attached to that identity. Enumerate what it can touch — s3 ls, sts get-caller-identity, a DynamoDB scan — but stay read-only and stop the second you confirm access. An over-permissive guest role that lists a private S3 bucket is a strong, clean report.
Token scope and app client weaknesses
Check whether the app client allows the implicit grant, has no client secret where it should, or accepts overly broad OAuth scopes. Decode the ID and access tokens at [jwt.io] locally and read the claims. If the app authorizes actions based on a claim the user can influence, that's your chain.
Confirm the token audience and issuer are validated server-side. A backend that accepts any valid Cognito JWT — including one from a different app client in the same pool — is trusting the signature without checking who it was minted for.
Reporting without tripping GuardDuty
Scope everything to accounts and identities you created. Don't enumerate other users, don't touch data outside your own tenant, and don't rack up API volume that looks like an attack. One get-caller-identity proving you hold guest credentials is worth more than a noisy S3 crawl.
In the report, include the pool and client IDs, the exact CLI calls, the returned role ARN or attribute, and a plain statement of what a real attacker gains. Recommend disabling guest access unless required, scoping identity-pool IAM roles to least privilege, marking security attributes read-only, and validating token audience server-side.
The Amazon Cognito Developer Guide documents the User Pool / Identity Pool split and the attribute permission model — read the "app client settings" and "role-based access control" sections before you write up severity.