| name | apply-serverless-function-security |
| description | Use when writing serverless functions (AWS Lambda, Google Cloud Functions, Azure Functions) — validating event data from all trigger sources, preventing execution flow manipulation, and securing error handling. |
| source | OWASP Serverless Top 10 SLS-1 SLS-9 SLS-10 (owasp.org/www-project-serverless-top-10/); AWS Lambda security documentation; Palo Alto Unit 42 serverless research |
| tags | ["security","owasp","serverless","lambda","event-injection","cloud","developer"] |
Apply Serverless Function Security
Validate all event data at function entry regardless of trigger source, prevent execution flow manipulation by isolating functions to single responsibilities, and return generic error messages — preventing injection attacks that exploit the expanded attack surface of serverless event sources.
Why This Is Best Practice
Adopted by: OWASP Serverless Top 10 SLS-1 (Function Event Data Injection), SLS-9 (Serverless Function Execution Flow Manipulation), and SLS-10 (Improper Exception Handling). AWS Lambda security documentation mandates input validation for all event sources. Palo Alto Unit 42's "Serverless Security: A Deep Dive" (2021) identified event injection as the primary novel attack vector in serverless architectures. Netflix, Airbnb, and Capital One — all heavy Lambda users — treat Lambda event payloads as untrusted input from their first public serverless security guidance.
Impact: Unlike web applications where requests come through a single HTTP gateway, Lambda functions receive events from S3, SQS, SNS, DynamoDB Streams, API Gateway, EventBridge, and IoT — each with a different event schema and different injection surfaces. Palo Alto Unit 42 demonstrated SQL injection via S3 object key names that triggered Lambda functions. The 2022 Lacework serverless threat report found 35% of Lambda vulnerabilities were injection flaws introduced through non-HTTP event sources that developers didn't treat as attack vectors.
Why best: Traditional web input validation (request body + query params) misses serverless-specific injection paths: filenames in S3 events, message bodies in SQS, record data in DynamoDB Streams, and environment variable injection. Treating every event field as untrusted and validating schema at function entry closes these gaps vs. validating only API Gateway parameters.
Sources: OWASP Serverless Top 10 SLS-1, SLS-9, SLS-10; AWS Lambda security best practices; Palo Alto Unit 42 Serverless Security (2021); Lacework Cloud Security Report (2022)
Steps
-
Validate all event fields regardless of trigger source:
import json
import re
from pydantic import BaseModel, validator
class S3EventRecord(BaseModel):
bucket_name: str
object_key: str
@validator("object_key")
def no_path_traversal(cls, v):
if ".." in v or v.startswith("/"):
raise ValueError("Invalid object key")
if not re.match(r'^[\w\-./]+$', v):
raise ValueError("Object key contains invalid characters")
return v
def lambda_handler(event, context):
for record in event.get("Records", []):
if record.get("eventSource") == "aws:s3":
try:
validated = S3EventRecord(
bucket_name=record["s3"]["bucket"]["name"],
object_key=record["s3"][][]
)
Exception e:
()
{: , : }
process_s3_object(validated.bucket_name, validated.object_key)
Rules
- Every Lambda trigger source (S3, SQS, SNS, DynamoDB Streams, EventBridge, IoT, Cognito) is an untrusted input surface — validate schema before processing.
- Never use event fields directly in shell commands, SQL queries, or file paths without validation —
subprocess.run(event["command"]) is direct command injection.
- Dead Letter Queues (DLQ) must be configured for async invocations — without DLQ, failed events are silently dropped.
- Function names, ARNs, and environment variable names must not be included in error responses — they aid enumeration.
Common Mistakes
- Validating only API Gateway events — S3, SQS, and DynamoDB Stream events are equally injectable; treat all event sources as untrusted.
- Catching
Exception and returning str(e) — Python exception messages often contain table names, file paths, or SQL snippets; log internally, return generic message externally.
- No DLQ on async-triggered functions — if an S3-triggered Lambda fails, the event is silently lost; configure DLQ to SQS for investigation.
- Large monolithic functions with many code paths — a single Lambda doing read/write/admin based on an event field is SLS-9 (execution flow manipulation); split into separate functions.