While this does not qualify for a vulnerability or CVE, there’s an interesting aspect to cover on how AWS customers keep AWS solutions up to date and assess its security.
Details
- The service has a CloudFront, S3, and API Gateway that serves the front end.
- The publicly exposed API is an interface that interacts with images in S3 buckets.
- The Service has a Lambda with permission to retrieve objects from any S3 in the affected version.
- The code has a logic to only serve content from an S3 configured in the Lambda environment variable.
Through our research, we discovered a case where the Source Bucket was set to ‘.*’, effectively allowing images of the supported types to be exported from any bucket in the account.
While this does not affect the latest version, where the IAM Policy for the Lambda function is constrained to the bucket provided upon deployment, many instances are likely running an outdated version, and some configurations may have unintended buckets in the configuration or a wildcard similar to our findings.
The issue
The Policy Statement in versions prior to 5.2.6 defines resource ‘’* for S3, and the image-request.ts file will process any value in the sourceBuckets environment variable, including a wildcard specified in the image-request.ts:
if (sourceBuckets.includes(request.bucket) || new RegExp("^" + sourceBuckets[0] + "$").exec(request.bucket)) {
Abusing the function
Once its deployed, you can modify and abuse the function to exfiltrate images. Access the Lambda and update the SOURCE_BUCKET variable to match the bucket you want to access images in or set a wildcard.
From the CloudFormation Stack, access either the DemoUrl (if that was deployed) or the ApiEndpoint that can be found in the stack outputs:
In the case the solution was deployed with DemoUI, you can visit the DemoUrl and specify any bucket and any image, and it will be returned directly:
In the event where the DemoUrl wasn't deployed, you can query the API directly with a base64 encoded query:
echo -n '{
"bucket": "stealfrombucketserverless",
"key": "1.png",
"edits": {
"grayscale": true
}
}' | openssl base64
Below is an example where I am retrieving an image from a bucket and using the Serverless Image Handler to transform it into grayscale:
The fix in version 6.2.6
Comparing the version 6.2.5 to version 6.2.6, we can see that it removes the regex matching portion that allows the wildcard to be specified. By removing the regex evaluation and only keeping the strict string comparison with includes(), bucket names must exactly match what's specified in SOURCE_BUCKETS - there's no way for pattern matching to bypass this restriction.
Further, we can see that the version 6.2.6 properly restricts the S3 Buckets accessible to the Lambda functions IAM role, by specifying the exact buckets that are provided upon deployment of the solution - meaning that changing the environment variable won’t be sufficient to access images in other buckets.
Reproduction steps
- Clone the repository: https://github.com/aws-solutions/dynamic-image-transformation-for-amazon-cloudfront
- Checkout the version for 6.2.5
- Build the solution following the instructions in README.
- Change the environment variable to: .*
Why this matters
Unlike most software, AWS Solutions aren’t covered by CVEs as they are solutions built on top of the cloud. This might be a challenge, as clients that deployed a solution has no standardized way of tracking which version they are running or whether its vulnerable if an advisory was to be released. No code will ever be free of bugs, and in the event where this was a more critical vulnerability, we are not confident organizations would be in a position to opitimize their response.
While the likelihood that you are impacted by this is low, there may be instances where it can have unintended consequences, such as where sensitive images have later been uploaded to a bucket.