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-004 --project .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 asyncio.create_subprocess_shell() calls within async Lambda handlers.
Lambda functions increasingly use async/await patterns with asyncio for concurrent I/O operations. asyncio.create_subprocess_shell() is the async equivalent of subprocess.run(shell=True) and carries the same shell injection risk: the command string is passed to /bin/sh for interpretation, and any shell metacharacters in the event data will be executed as shell syntax.
Lambda functions receive input from the event dictionary populated by API Gateway, SQS, SNS, S3, DynamoDB Streams, and other triggers. Fields like event.get("body"), event.get("queryStringParameters"), and event["Records"] are attacker-controllable. There is no sanitization layer between the event payload and application code.
The async nature of the handler does not provide any additional security for shell commands. Injected commands run asynchronously but still complete within the invocation timeout, allowing exfiltration of the Lambda execution role's AWS credentials (available in environment variables) and other sensitive data before the invocation ends.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Shell Injection in Async Lambda Handlers
asyncio.create_subprocess_shell() passes the command string to /bin/sh for execution. Lambda event data embedded via f-strings or concatenation allows an attacker to inject shell metacharacters (;, |, $(), ``) that chain additional commands. The async execution model does not prevent injection; commands run concurrently and complete before the handler returns.
AWS Credential Exfiltration via Async Shell
The Lambda execution environment exposes AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN as environment variables. An async shell injection can spawn a background process that exfiltrates these credentials via curl or wget to attacker-controlled infrastructure, completing before the Lambda invocation ends.
Concurrent Exploitation Amplification
Async handlers may process multiple event records concurrently (e.g., SQS batch processing). A batch of malicious SQS messages could trigger multiple concurrent injections within a single invocation, amplifying the attack surface and potentially overwhelming logging or detection systems.
VPC Lateral Movement
Lambda functions in a VPC have network access to internal resources. An async shell injection can initiate non-blocking outbound connections to internal endpoints (RDS, ElastiCache, internal APIs) that are not accessible from the internet, enabling lateral movement through the VPC.
How to Fix
Recommended remediation steps
- 1Replace asyncio.create_subprocess_shell() with asyncio.create_subprocess_exec() using individual arguments, which bypasses the shell entirely.
- 2Never interpolate Lambda event data into shell command strings, even with asyncio async patterns.
- 3Validate all event fields with strict allowlists or regular expressions before they appear in any subprocess or asyncio subprocess argument.
- 4Apply least-privilege IAM policies to the Lambda execution role to limit the AWS APIs accessible if credentials are exfiltrated.
- 5Enable AWS CloudTrail and VPC Flow Logs to detect unusual outbound connections from the Lambda execution environment.
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_shell") with the tainted command string tracked via .tracks(0). Sanitizers include shlex.quote() applied per-argument. The analysis follows taint through async function calls, await expressions, f-string interpolation, and module boundaries.
Compliance & Standards
Industry frameworks and regulations that require detection of this vulnerability
References
External resources and documentation
Similar Rules
Explore related security rules for Python
Lambda Command Injection via os.system()
Lambda event data flows to os.system(), enabling arbitrary OS command execution inside the Lambda execution environment.
Lambda Command Injection via subprocess
Lambda event data flows to subprocess with shell=True or as a string command, enabling OS command injection in the Lambda execution environment.
Lambda Command Injection via os.spawn*()
Lambda event data flows to os.spawn*() functions, enabling process execution with attacker-controlled arguments in the Lambda execution environment.
Frequently Asked Questions
Common questions about Lambda Command Injection via asyncio.create_subprocess_shell()
New feature
Get these findings posted directly on your GitHub pull requests
The Lambda Command Injection via asyncio.create_subprocess_shell() rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.