Skip to main content
CRITICALLambdaSecurity

Lambda Permission Permits Public Access

lambda-permission-public

What this rule checks

Detects AWS::Lambda::Permission and AWS::Lambda::LayerVersionPermission resources that grant invoke / use rights with a wildcard Principal, or grant a service principal without a SourceArn / SourceAccount / PrincipalOrgID restriction (confused-deputy risk).

How to fix it

  1. 1Replace wildcard Principal with a specific 12-digit AWS account ID or {Ref: AWS::AccountId}
  2. 2For service principals, set SourceArn to the specific resource that may invoke the function
  3. 3For S3 service principal, set SourceAccount to your AWS account ID
  4. 4For LayerVersionPermission, prefer OrganizationId over wildcard Principal
Flaggedfn.addPermission with an AnyPrincipal (Principal "*") and no source restriction grants invoke to any AWS account โ€” the check flags it CRITICAL public.
import * as iam from 'aws-cdk-lib/aws-iam';
import * as lambda from 'aws-cdk-lib/aws-lambda';

const fn = new lambda.Function(this, 'Fn', {
  runtime: lambda.Runtime.NODEJS_22_X,
  handler: 'index.handler',
  code: lambda.Code.fromInline('exports.handler = async () => {};'),
});
// Grants invoke to ANY AWS account with no source restriction โ€” public.
fn.addPermission('Public', {
  principal: new iam.AnyPrincipal(),
});
FixedThe permission is scoped to the S3 service principal with both a SourceArn and SourceAccount, so it is neither a wildcard nor unrestricted โ€” no finding.
import * as iam from 'aws-cdk-lib/aws-iam';
import * as lambda from 'aws-cdk-lib/aws-lambda';

const fn = new lambda.Function(this, 'Fn', {
  runtime: lambda.Runtime.NODEJS_22_X,
  handler: 'index.handler',
  code: lambda.Code.fromInline('exports.handler = async () => {};'),
});
// Scoped to the S3 service principal and a specific source bucket ARN.
fn.addPermission('FromBucket', {
  principal: new iam.ServicePrincipal('s3.amazonaws.com'),
  sourceArn: 'arn:aws:s3:::my-source-bucket',
  sourceAccount: '111122223333',
});

CDK Insights pinpoints the exact file and line in your CDK source for every finding, so you can jump straight to the fix.

Affected resource types

AWS::Lambda::PermissionAWS::Lambda::LayerVersionPermission

Compliance frameworks

SOC2HIPAAPCI-DSSNIST

AWS documentation

Read the AWS guidance

Intentional? Suppress this finding

Sometimes a flag is deliberate โ€” a genuinely public endpoint, say. You can dismiss lambda-permission-public and the reason is kept in the report, not silently hidden.

In .cdk-insights.json:

{
  "ignoreRules": [
    { "id": "lambda-permission-public", "reason": "Why this is intentional" }
  ]
}

Or inline in your CDK code:

Validations.of(scope).acknowledge({
  id: 'cdk-insights::lambda-permission-public',
  reason: 'Why this is intentional',
});

Use the rule ID lambda-permission-public shown above โ€” not the CDK-* ID from SARIF / GitHub code scanning. To dismiss every finding on one construct instead, use ignorePaths. Suppression docs โ†’

Catch this in your stack

$ npx cdk-insights scan

CDK Insights runs this and 118+ other rules locally against your synthesised CDK app โ€” free, no account, your code never leaves your machine.

More Lambda rules