Lambda Command Injection via asyncio.create_subprocess_exec()

CRITICAL

Lambda event data flows to asyncio.create_subprocess_exec(), enabling argument injection in async Lambda handlers.

Rule Information

Language
Python
Category
AWS Lambda
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonawslambdacommand-injectionasynciocreate-subprocess-execargument-injectiontaint-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-005 --project .
1
2
3
4
5
6
7
8
9
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

About This Rule

Understanding the vulnerability and how it is detected

This rule detects command injection vulnerabilities in AWS Lambda functions where untrusted event data flows into asyncio.create_subprocess_exec() calls within async Lambda handlers.

asyncio.create_subprocess_exec() does not invoke a shell and passes arguments directly to the process via execve(), making it the safer async subprocess API. However, it is still vulnerable to argument injection when event data controls the executable path (first argument) or argument values that the target binary interprets as flags or commands. Classic examples include passing attacker-controlled strings as filenames to tools like rsync, wget, or curl that interpret certain argument patterns as additional operations.

Lambda functions receive input from the event dictionary populated by API Gateway, SQS, SNS, S3, DynamoDB Streams, and other triggers. Fields such as event.get("body"), event.get("queryStringParameters"), and event["Records"] are fully attacker- controllable in public-facing deployments.

While the shell injection risk is reduced compared to create_subprocess_shell(), the risk of argument injection and executable path manipulation remains when event data is used in any argument position without validation.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Executable Path Hijacking

If event data controls the first argument (the executable path) of create_subprocess_exec(), an attacker can point the execution to any binary accessible in the Lambda filesystem, including user-written scripts in /tmp. Always use hardcoded, absolute executable paths from an allowlist.

2

Argument Injection via Flag-Like Values

Many command-line tools interpret arguments beginning with '-' as flags. If event data is passed as an argument without the '--' separator, values like '--exec', '--output', or '-rf' may activate unintended behaviors in the target binary. Prefix user-provided arguments with '--' when the target tool supports it.

3

AWS Credential Access via Argument Injection

Argument injection can cause tools like curl, wget, or rsync to write output files, follow redirects, or establish connections in ways that expose the Lambda execution environment's AWS credentials stored in environment variables.

4

/tmp Exfiltration and Modification

Argument injection into file processing tools can redirect output to attacker- controlled destinations, read arbitrary /tmp files, or overwrite Lambda deployment package files if /tmp is used for code storage.

How to Fix

Recommended remediation steps

  • 1Validate the executable argument against a hardcoded allowlist of absolute paths; never derive the executable from event data.
  • 2Prefix user-controlled filename arguments with '--' to prevent the target binary from interpreting them as flags.
  • 3Validate all event fields with strict allowlists or regular expressions before they appear in any argument position.
  • 4Apply least-privilege IAM policies to the Lambda execution role to minimize the AWS APIs accessible if exploitation occurs.
  • 5Prefer native Python libraries over subprocess calls wherever possible to eliminate the subprocess attack surface.

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"]. The sink is calls("asyncio.create_subprocess_exec") with tainted values tracked via .tracks(0) for the executable argument and additional argument positions. The analysis follows taint through async function calls, await expressions, list construction, and module 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 asyncio.create_subprocess_exec()

create_subprocess_exec() bypasses the shell, so classic shell injection with semicolons, pipes, and $() does not work. However, argument injection remains a risk: if event data controls the executable path, it can point to any binary in the Lambda filesystem. If event data controls argument values, many tools interpret arguments starting with '-' as flags, potentially activating unintended behaviors. Always validate executable paths and argument values from allowlists.
SEC-004 covers create_subprocess_shell(), which always invokes the shell and is vulnerable to shell metacharacter injection. SEC-005 covers create_subprocess_exec(), which does not invoke a shell but is still vulnerable to argument injection when event data controls argument positions. Both rules are needed because developers sometimes switch from shell to exec thinking it eliminates all injection risk, when argument injection remains possible without input validation.
The '--' argument is a POSIX convention that signals the end of flag arguments to most command-line tools. Arguments after '--' are treated as positional arguments (filenames, etc.) rather than flags. Prefixing user-provided filenames with '--' prevents the tool from interpreting values like '--delete' or '-rf' as flags. Use '--' before any argument derived from event data in all subprocess calls.
No. Even a strict regex validation on an executable path does not guarantee safety, because an attacker may craft a path that passes the regex but still points to an unintended binary. Always use a hardcoded dictionary or set of allowed executables with their full absolute paths, and use the event data only to select a key from that allowlist, never to construct the path itself.
For SQS batch processing, iterate over event["Records"] and process each record in separate async tasks. Validate each record's fields individually before use in subprocess calls. Implement SQS batch item failure reporting so that a single malformed record that fails validation does not cause the entire batch to be retried.

New feature

Get these findings posted directly on your GitHub pull requests

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

See how it works