Skip to main content

Lambda Function URL CORS Does Not Allow Wildcard Origins

Overview

This check examines AWS Lambda function URL CORS (Cross-Origin Resource Sharing) configurations to identify if wildcard origins (*) are permitted. CORS controls which websites can call your Lambda function URL from a browser. When you allow all origins with a wildcard, any website on the internet can make requests to your function.

Risk

Allowing wildcard origins in your Lambda function URL creates several security vulnerabilities:

  • Data exposure: Any website can call your endpoint and read the response, potentially exposing sensitive data
  • Unauthorized actions: Malicious sites can trigger state-changing operations on behalf of unsuspecting users
  • Cross-origin attacks: Attackers can craft malicious web pages that exploit your function
  • Credential theft: If AllowCredentials is also enabled, cookies and authentication headers can be stolen

Remediation Steps

Prerequisites

  • AWS account access with permissions to modify Lambda function URLs
  • Knowledge of which domains legitimately need to call your function
Required IAM permissions

You will need the following permissions:

  • lambda:GetFunctionUrlConfig - View current function URL configuration
  • lambda:UpdateFunctionUrlConfig - Modify CORS settings
  • lambda:ListFunctionUrlConfigs - List all function URLs (optional)

AWS Console Method

Step 1: Navigate to your Lambda function

  1. Sign in to the AWS Management Console
  2. Navigate to Lambda > Functions
  3. Select the Lambda function flagged by Prowler

Step 2: View the current Function URL configuration

  1. Click the Configuration tab
  2. In the left sidebar, click Function URL
  3. Review the current CORS settings under "Cross-origin resource sharing (CORS)"

Step 3: Update CORS to use specific origins

  1. Click Edit next to the Function URL configuration
  2. Scroll to the Cross-origin resource sharing (CORS) section
  3. Under Allow origin, remove the wildcard (*) and add your specific trusted domains:
    • Example: https://www.example.com
    • Example: https://app.example.com
  4. Optionally, restrict other CORS settings:
    • Allow headers: List only headers your function needs (e.g., Content-Type, Authorization)
    • Allow methods: Select only the HTTP methods your function uses (e.g., GET, POST)
    • Allow credentials: Disable unless your function requires cookies or authentication headers
    • Max age: Set a reasonable cache duration (e.g., 3600 seconds)
  5. Click Save
AWS CLI (optional)

View current CORS configuration:

aws lambda get-function-url-config \
--function-name <your-function-name> \
--region us-east-1

Update CORS to allow specific origins:

aws lambda update-function-url-config \
--function-name <your-function-name> \
--cors '{
"AllowOrigins": ["https://www.example.com", "https://app.example.com"],
"AllowMethods": ["GET", "POST"],
"AllowHeaders": ["Content-Type", "Authorization"],
"AllowCredentials": false,
"MaxAge": 3600
}' \
--region us-east-1

Using shorthand syntax:

aws lambda update-function-url-config \
--function-name <your-function-name> \
--cors 'AllowOrigins=https://www.example.com,https://app.example.com,AllowMethods=GET,POST,AllowHeaders=Content-Type,Authorization,AllowCredentials=false,MaxAge=3600' \
--region us-east-1

List all function URLs to find affected functions:

aws lambda list-functions \
--region us-east-1 \
--query 'Functions[*].FunctionName' \
--output text | tr '\t' '\n' | while read fn; do
aws lambda get-function-url-config --function-name "$fn" --region us-east-1 2>/dev/null
done
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: Lambda function with secure CORS configuration

Parameters:
AllowedOrigin:
Type: String
Default: 'https://www.example.com'
Description: The origin allowed to access this function URL

Resources:
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: SecureLambdaExecutionRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

MyLambdaFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: my-secure-function
Runtime: python3.12
Handler: index.lambda_handler
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: |
def lambda_handler(event, context):
return {
'statusCode': 200,
'body': 'Hello from Lambda!'
}

LambdaFunctionUrl:
Type: AWS::Lambda::Url
Properties:
AuthType: AWS_IAM
TargetFunctionArn: !GetAtt MyLambdaFunction.Arn
Cors:
AllowOrigins:
- !Ref AllowedOrigin
AllowMethods:
- GET
- POST
AllowHeaders:
- Content-Type
- Authorization
AllowCredentials: false
MaxAge: 3600

LambdaFunctionUrlPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref MyLambdaFunction
Action: lambda:InvokeFunctionUrl
Principal: '*'
FunctionUrlAuthType: AWS_IAM

Outputs:
FunctionUrl:
Description: The Lambda function URL
Value: !GetAtt LambdaFunctionUrl.FunctionUrl
FunctionArn:
Description: The Lambda function ARN
Value: !GetAtt MyLambdaFunction.Arn

Deploy the template:

aws cloudformation deploy \
--template-file lambda-secure-cors.yaml \
--stack-name lambda-secure-cors-stack \
--parameter-overrides AllowedOrigin=https://www.example.com \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-1
Terraform (optional)
provider "aws" {
region = "us-east-1"
}

variable "allowed_origins" {
type = list(string)
default = ["https://www.example.com", "https://app.example.com"]
description = "List of origins allowed to access the Lambda function URL"
}

# IAM role for Lambda
resource "aws_iam_role" "lambda_role" {
name = "secure-lambda-execution-role"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
}]
})
}

# Attach basic execution policy
resource "aws_iam_role_policy_attachment" "lambda_basic" {
role = aws_iam_role.lambda_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

# Lambda function
resource "aws_lambda_function" "my_function" {
filename = "function.zip"
function_name = "my-secure-function"
role = aws_iam_role.lambda_role.arn
handler = "index.lambda_handler"
runtime = "python3.12"
source_code_hash = filebase64sha256("function.zip")
}

# Lambda function URL with secure CORS
resource "aws_lambda_function_url" "my_function_url" {
function_name = aws_lambda_function.my_function.function_name
authorization_type = "AWS_IAM"

cors {
allow_origins = var.allowed_origins
allow_methods = ["GET", "POST"]
allow_headers = ["Content-Type", "Authorization"]
allow_credentials = false
max_age = 3600
}
}

output "function_url" {
description = "The Lambda function URL"
value = aws_lambda_function_url.my_function_url.function_url
}

Verification

After completing the remediation:

  1. Navigate to Lambda > Functions > your function in the AWS Console
  2. Click Configuration > Function URL
  3. Verify that "Allow origin" shows your specific domains, not *
  4. Test your application to ensure legitimate cross-origin requests still work
  5. Re-run the Prowler check to confirm the issue is resolved
CLI verification commands

Verify the CORS configuration:

aws lambda get-function-url-config \
--function-name <your-function-name> \
--region us-east-1 \
--query 'Cors'

Test that wildcard is no longer present:

aws lambda get-function-url-config \
--function-name <your-function-name> \
--region us-east-1 \
--query 'Cors.AllowOrigins' \
--output text | grep -q '\*' && echo "FAIL: Wildcard still present" || echo "PASS: No wildcard origin"

Additional Resources

Notes

  • Consider IAM authentication: If your function handles sensitive data, use AWS_IAM authentication type instead of NONE for an additional layer of security
  • AllowCredentials warning: If you enable AllowCredentials: true, you cannot use wildcard origins anyway (browsers enforce this restriction), but you should still specify only trusted origins
  • Development environments: For local development, you may add http://localhost:3000 to allowed origins, but ensure this is removed in production
  • Multiple origins: Lambda function URLs support up to 100 allowed origins, so you can specify all legitimate domains that need access
  • API Gateway alternative: For more granular CORS control and additional security features, consider using API Gateway with Lambda integration instead of Lambda function URLs