Secure Infrastructure

Amazon Cognito – A Quick Look Into Token Security

If you’re using Amazon Cognito to manage user authentication in your application, you should be aware of the permissions users have by default when issued an access token. These could be abused to overwrite user custom attributes, leading to privilege escalation within the application.

Amazon Cognito Tokens Used the Unintended Way

If you’re using Amazon Cognito to manage user authentication in your application, you should be aware of the permissions users have by default when issued an access token.

When signing in to an application that uses Amazon Cognito for authentication, three tokens are returned to the user: an ID token, an access token, and a refresh token.

The assigned scope defines the token’s access level to the user. When the token scope is set to “aws.cognito.signin.user.admin,” the user has permission to view and edit their user attributes stored within Cognito (e.g., username, email, custom attributes, etc.)!

Please note that the “aws.cognito.signin.user.admin” is the default scope when creating a user pool, and it’s commonly seen in implementations.

Access Token Example

Here is an example of an access token issued by Amazon Cognito.

{
 "sub": "2688e2f5-0297-4b74f-c720-13663f612fe",
 "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_25pdG8uA",
 "client_id": "<redacted>",
 "origin_jti": "1fc9d20d-bb4e-9b81-7c86-cfd563f617ab",
 "event_id": "986cf210-127b-62e1-b9d3-a73f63f6179a",
 "token_use": "access",
 "scope": "aws.cognito.signin.user.admin",
 "auth_time": 16770234287,
 "exp": 1677065387,
 "iat": 1677057687,
 "jti": "d044678d-9ff7-28a1-ff28-00c663f61789",
 "username": "ab048e9-f3ed-6d9f-2685-dbbf963f6134e"
}

As seen in the JWT token, the “scope” set to “aws.cognito.signin.user.admin” allows the user to view and change their own attributes if otherwise restricted by an administrator.

Change User Attributes Attack

The figure below simply illustrates the attack, wherein a token with the overly permissive scope is issued, then a user attribute is changed.

aws toke cognito flow change user attributes
AWS Cognito flow – change user attribute

The scope allows the token to view and modify the user’s attributes. These attributes can be easily shown with the use of AWS CLI.

aws cognito-idp get-user --access-token "eyJraWQi........5d5LVkQ" | jq . 

{ 
 "Username": "ab048e9-f3ed-6d9f-2685-dbbf963f6134e", 
 "UserAttributes": [ 
 { 
 "Name": "custom:full_name", 
 "Value": "testcarlo" 
 }, 
 { 
 "Name": "sub", 
 "Value": "ab048e9-f3ed-6d9f-2685-dbbf963f6134e" 
 }, 
 { 
 "Name": "custom:app_uid", 
 "Value": "12345" 
 }, 
 { 
 "Name": "custom:user_advanced_features", 
 "Value": "false" 
 },
 { 
 "Name": "custom:member_admin", 
 "Value": "false" 
 }, 
 { 
 "Name": "email", 
 "Value": "carlotest@company.local" 
 } 
 ] 
}

Depending on how you integrate Amazon Cognito into your application, developers can rely on these custom attributes to define the user’s role or group. Applications can verify user privileges based on these fields, thus the importance of scoping down permissions whenever possible.

The user being able to modify their own fields can result in horizontal (user takeover) and vertical (role/group permissions change) privilege escalation.

An example would be to change a UID or a role membership field to a more privileged one. This can be accomplished with another AWS CLI command as follows:

$ aws cognito-idp update-user-attributes --access-token "eyJraWQi.....5d5LVkQ" --user-attributes '[{"Name":"custom:app_uid","Value":"1000"}]' 

By updating these attributes, the user can now change the group or role, depending on how the integration with the application is set up. Group and roles are examples; any interesting writeable field can be useful to the case.

In our test example, the Cognito user admin custom attribute is checked by the application to grant a different level of access. Once the attribute has been changed, the application will return an admin context to the user, as shown in the figure below.

cognito flow user admin
User context is now admin.

Cognito User Email Change

In the case of email change, Amazon Cognito recently introduced the “Verifying attribute changes” user pool setting; you can read more here, which enforces the user to confirm the email/phone number before considering valid the new value. This can potentially lead to user takeover, depending on how the integrated applications used handle this value.

Verifying attribute changes setting
Verifying attribute changes setting

If this setting is “Disabled,” a user able to change the email field can overwrite the email field without the need to validate it.

Mitigation

There are at least three steps that can restrict the user from modifying their own attributes:

  • Change the scope of the token, assigning only the required permissions.
  • Set the user attributes to immutable (or not writeable) from AWS Cognito settings.
  • Directly block the API function call through AWS Web Application Firewall, either through an allowlist of Amazon Cognito functions allowed (recommended) or through a denylist of the function
In regard to the verification of changed attributes, such as phone number or email, ensure that the “Verifying attribute changes” setting is correctly set, either with “phone_number” or “email.”