Skip to content

Research on the enumeration of IAM permissions without logging to CloudTrail

Notifications You must be signed in to change notification settings


Repository files navigation


Research on the enumeration of IAM permissions without logging to CloudTrail

Update 6/2/2021

All good things must come to an end :( This flaw has been fixed by AWS and the technique no longer works. This repo will stay around as a historical artifact.


As of 10/16/2020 there exists a vulnerability in the AWS API that allows you to enumerate some IAM permissions for a role without logging to CloudTrail. This capability is due to improper handling of the Content-Type header which is important for the AWS API. It currently affects the following AWS services.

  • application-autoscaling
  • appstream
  • athena
  • autoscaling-plans
  • aws-marketplace
  • cloudhsm
  • codecommit
  • codepipeline
  • codestar
  • comprehend
  • cur
  • datapipeline
  • dax
  • discovery
  • forecast
  • health
  • identitystore
  • kinesis
  • kinesisanalytics
  • macie
  • mediastore
  • mgh
  • mturk-requester
  • opsworks-cm
  • redshift-data
  • route53domains
  • route53resolver
  • sagemaker
  • secretsmanager
  • shield
  • sms
  • snowball
  • support
  • tagging
  • textract
  • translate
  • workmail

Update 12/19/2020: DirectConnect no longer appears to be vulnerable to this issue.

Update 4/21/2020: GameLift and Personalize no longer appear to be vulnerable to this issue, and broke a previous proof of concept.

Note: not all API calls for these services are vulnerable. For a complete list of every vulnerable API call please see /enum_all_api_calls/final-vuln-api-list.txt.

Please see this blog post for more details.

Steps to Reproduce

The vulnerability only affects AWS services that use POST requests and the X-Amz-Target header (Each AWS API has different implementations. Some use GET requests, some POST to an API endpoint, etc). The majority of these services require the Content-Type header to be 'application/x-amz-json-1.1'. In the majority of instances, sending 'application/x-amz-json-1.0' will provide you with an error; typically 404 - 'UnknownOperationException' or 500 - 'InternalFailure'.

However, on the services listed above you instead will get a 403 response if you do not have permission to call the API. If the role does have permission to call the API you instead get a 404. Because these are technically "malformed" requests none of this traffic is sent to CloudTrail, meaning you can enumerate whether or not a given role has privileges to make the API call without that reconnaissance being logged.

There are some caveats that should be noted, however. Let's take Secrets Manager for example. Within Secrets Manager there are two API calls which automatically set their value to resource:*, those are secretsmanager:ListSecrets and secretsmanager:GetRandomPassword.

Now, if you use the vulnerability without your current role having permissions to call the secretsmanager:ListSecrets action you will get a 403 response as shown below.

403 response

However, if you modify the IAM policy to include privileges for these two actions, it will default to resource:*, and give you the following text.

The actions you chose support all resources

And when rendered via JSON you get the following.

Showing permissions.

After allowing those permissions to take effect, if you run the same script again, you will receive a 404 response as shown below.

404 response

Depending on the 403 or 404 response you will know whether or not the role has permission to call the secretsmanager:ListSecrets action. There are many AWS API call's which only work with resource:*, these are just two.

For more specific actions let's look at secretsmanager:GetSecretValue.

If the role does not have this permission, and we make the request we will get a 403 response (regardless of whether or not the secret id is real or not).

403 get secret

If you do provide the role the IAM permissions to get a specific secret, and then query that specific secret or one that does not exist, you will still get a 403 response. Because of this, if the IAM policy is locked to a specific ARN, you will not be able to enumerate the permission using this method.

403 get secret

However, if you instead modify the IAM policy to allow resource:* as shown below...

IAM Resources

You will get a 404 response.

404 response

For whatever reason, when parsing the API query given the Content-Type: x-amz-json-1.0 header, the API service will return different response codes allowing us to determine our IAM permissions without logging to CloudTrail. From an attackers perspective, if you get a 404 response, you know the IAM action and whether or not the resource is set to *.

Proof of Concept

If you would like to test this for yourself, create a role with the example policy (in this repo) and then create the temporary credentials to assume the role (don't forget to set them in your environment variables). From there, run the proof of concept script, and it will determine what permissions you do and do not have access to. Wait 15-30 minutes, and then confirm that those API calls were not tracked in CloudTrail.

Please note, the tool has a list of API calls it checks. It will not enumerate every single API call for each vulnerable API service.


Not in CloudTrail


Research on the enumeration of IAM permissions without logging to CloudTrail






No releases published


No packages published