Detection rules › Elastic

AWS Lambda Function Policy Updated to Allow Public Invocation

Status
production
Severity
medium
Time window
6m
Author
Elastic
Source
github.com/elastic/detection-rules

Identifies when an AWS Lambda function policy is updated to allow public invocation. This rule detects use of the AddPermission API where the Principal is set to "*", enabling any AWS account to invoke the function. Adversaries may abuse this configuration to establish persistence, create a covert execution path, or operate a function as an unauthenticated backdoor. Public invocation is rarely required outside very specific workloads and should be considered high-risk when performed unexpectedly.

MITRE ATT&CK coverage

Event coverage

ProviderEventTitle
AWS-lambda_catch_allAWS-lambda (catch-all)

Rules detecting the same action

Other rules on this platform that filter on the same API call or operation.

Rule body elastic

[metadata]
creation_date = "2024/04/30"
integration = ["aws"]
maturity = "production"
updated_date = "2026/04/10"

[rule]
author = ["Elastic"]
description = """
Identifies when an AWS Lambda function policy is updated to allow public invocation. This rule detects use of the
AddPermission API where the Principal is set to "*", enabling any AWS account to invoke the function. Adversaries may
abuse this configuration to establish persistence, create a covert execution path, or operate a function as an
unauthenticated backdoor. Public invocation is rarely required outside very specific workloads and should be considered
high-risk when performed unexpectedly.
"""
event_category_override = "event.type"
false_positives = [
    """
    Some organizations may legitimately expose Lambda functions for cross-account or anonymous invocation (e.g., custom
    public APIs, integrations, or legacy architectures). Validate whether the function owner explicitly intended to make
    the function publicly invokable. Routine CI/CD deployments or IaC templates may also temporarily set permissive
    policies; confirm this is expected behavior before treating it as suspicious.
    """,
]
from = "now-6m"
index = ["filebeat-*", "logs-aws.cloudtrail-*"]
language = "eql"
license = "Elastic License v2"
name = "AWS Lambda Function Policy Updated to Allow Public Invocation"
note = """## Triage and analysis

### Investigating AWS Lambda Function Policy Updated to Allow Public Invocation

AWS Lambda policies control who can invoke a function. When the `Principal` is set to `*`, the function becomes publicly invokable by any AWS account. Adversaries may modify Lambda permissions to create a stealthy execution backdoor or to maintain persistence inside an AWS environment. This activity is uncommon in most production environments and should receive careful scrutiny when detected.

### Possible investigation steps

**Identify the actor**
- Identify the actor who made the change by reviewing `aws.cloudtrail.user_identity.arn` and access key ID. Determine whether this principal typically administers Lambda functions.

**Review request details**
- Review request details in `aws.cloudtrail.request_parameters` to understand the exact permission added:
  - Confirm that the `Principal` is set to `"*"`.
  - Note the `Action` (`lambda:InvokeFunction`) and any `SourceArn` restrictions (sometimes present, often missing in malicious cases).

**Analyze source context**
- Check the source of the request using `source.ip`, geo information, and user agent. Unexpected networks, automation tools, or CLI usage may indicate credential compromise.

**Correlate timing and related events**
- Evaluate timing and sequence by correlating `@timestamp` with other events. Look for surrounding actions such as:
  - Creation or update of Lambda function code.
  - Publishing new Lambda layers.
  - Changes to roles attached to the function.

**Assess function sensitivity and impact**
- Assess the function’s role and data sensitivity. Determine whether public invocation could:
  - Enable unmonitored code execution,
  - Trigger access to internal resources via the function’s IAM role,
  - Be chained with persistence or privilege escalation behavior.

**Validate operational intent**
- Validate the operational context. Confirm with the function owner whether the permission change was intentional, part of a deployment, or unexpected.

### False positive analysis

- Public invocation may be intentional for certain workloads (e.g., webhook handlers, openly accessible compute functions). Compare the event with documentation, IaC templates, or the deployment pipeline.
- Some teams may regularly modify permissions during testing or refactoring; check whether this aligns with existing workflows.
- Evaluate whether the function already had permissive invocation policies and whether the update is part of expected configuration drift.

### Response and remediation

- Remove unauthorized public invocation permissions immediately by reverting the Lambda function policy to the approved baseline.
- Investigate for follow-on activity: execution of the function, updates to code, modifications to IAM roles, or API calls issued using the function's role.
- Rotate or disable credentials associated with the identity that issued the `AddPermission` call if compromise is suspected.
- Enable or refine monitoring for Lambda policy updates, layer additions, and code changes to detect future unauthorized modifications.
- Conduct a security review of the Lambda function and any downstream resources it can access to ensure no misuse has occurred.
- Work with the application team to enforce least-privilege invocation policies and deploy guardrails (e.g., SCPs, IAM Conditions, or automated compliance checks) preventing public invocation unless explicitly authorized.

### Additional information
- **[AWS IR Playbooks](https://github.com/aws-samples/aws-incident-response-playbooks/blob/c151b0dc091755fffd4d662a8f29e2f6794da52c/playbooks/)** 
- **[AWS Customer Playbook Framework](https://github.com/aws-samples/aws-customer-playbook-framework/tree/a8c7b313636b406a375952ac00b2d68e89a991f2/docs)** 
- **[AWS Knowledge Center – Security Best Practices](https://aws.amazon.com/premiumsupport/knowledge-center/security-best-practices/)**
"""
references = [
    "https://cloud.hacktricks.xyz/pentesting-cloud/aws-security/aws-persistence/aws-lambda-persistence",
    "https://stratus-red-team.cloud/attack-techniques/AWS/aws.persistence.lambda-backdoor-function/",
    "https://docs.aws.amazon.com/lambda/latest/api/API_AddPermission.html",
]
risk_score = 47
rule_id = "151d8f72-0747-11ef-a0c2-f661ea17fbcc"
severity = "medium"
tags = [
    "Domain: Cloud",
    "Data Source: AWS",
    "Data Source: Amazon Web Services",
    "Data Source: AWS Lambda",
    "Use Case: Threat Detection",
    "Tactic: Persistence",
    "Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "eql"

query = '''
info where data_stream.dataset == "aws.cloudtrail" 
    and event.provider == "lambda.amazonaws.com" 
    and event.outcome == "success" 
    and event.action : "AddPermission*" 
    and stringContains(aws.cloudtrail.request_parameters, "lambda:InvokeFunction") 
    and stringContains(aws.cloudtrail.request_parameters, "principal=\\*")
'''


[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1546"
name = "Event Triggered Execution"
reference = "https://attack.mitre.org/techniques/T1546/"

[rule.threat.tactic]
id = "TA0003"
name = "Persistence"
reference = "https://attack.mitre.org/tactics/TA0003/"

[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1578"
name = "Modify Cloud Compute Infrastructure"
reference = "https://attack.mitre.org/techniques/T1578/"

[[rule.threat.technique.subtechnique]]
id = "T1578.005"
name = "Modify Cloud Compute Configurations"
reference = "https://attack.mitre.org/techniques/T1578/005/"

[rule.threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"
[rule.investigation_fields]
field_names = [
    "@timestamp",
    "user.name",
    "user_agent.original",
    "source.ip",
    "aws.cloudtrail.user_identity.arn",
    "aws.cloudtrail.user_identity.type",
    "aws.cloudtrail.user_identity.access_key_id",
    "event.action",
    "event.outcome",
    "cloud.account.id",
    "cloud.region",
    "aws.cloudtrail.request_parameters",
    "aws.cloudtrail.response_elements",
]

Stages and Predicates

Stage 1: info

info where data_stream.dataset == "aws.cloudtrail" 
    and event.provider == "lambda.amazonaws.com" 
    and event.outcome == "success" 
    and event.action : "AddPermission*" 
    and stringContains(aws.cloudtrail.request_parameters, "lambda:InvokeFunction") 
    and stringContains(aws.cloudtrail.request_parameters, "principal=\\*")

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
aws.cloudtrail.request_parameterscontains
  • lambda:InvokeFunction
  • principal=\*
data_stream.dataseteq
  • aws.cloudtrail
event.actionwildcard
  • AddPermission*
event.outcomeeq
  • success
event.providereq
  • lambda.amazonaws.com