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-LANG-SEC-012 --project .About This Rule
Understanding the vulnerability and how it is detected
Python's os.spawnl(), os.spawnle(), os.spawnlp(), os.spawnlpe(), os.spawnv(), os.spawnve(), os.spawnvp(), and os.spawnvpe() functions spawn a new process to execute an external program. These functions are an older API for process creation and have been superseded by the subprocess module, which provides more control, better error handling, and a safer interface.
The spawn functions with the 'p' suffix (spawnlp, spawnvp) search PATH for the executable, which introduces additional risk if PATH can be manipulated. The 'e' suffix variants accept an explicit environment, which can be exploited if constructed from user input.
When the executable path or any argument is derived from untrusted input, an attacker can cause arbitrary program execution. Even the list-based variants (spawnv) that do not invoke a shell are dangerous when the executable path is attacker-controlled.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Arbitrary Program Execution
An attacker controlling the executable path argument can run any program on the system. The spawned process runs with the same user credentials as the Python process, giving the attacker the same filesystem and network access.
PATH-Based Executable Hijacking
The spawnlp and spawnvp variants search PATH to find the executable. If PATH can be manipulated via environment injection or if the current working directory is included in PATH, an attacker can place a malicious binary named after the target executable to intercept the spawn call.
Environment Variable Injection
The spawnle and spawnve variants accept a custom environment dictionary. If this dictionary incorporates user-supplied values, an attacker can set LD_PRELOAD to inject shared library code, or manipulate PATH to control which binaries are found.
Resource Leak and Missing Error Handling
os.spawn*() provides less robust error handling than subprocess. Failures may leave zombie processes, uncollected exit codes, and unclosed file descriptors, which can be exploited for denial-of-service through resource exhaustion.
How to Fix
Recommended remediation steps
- 1Replace all os.spawn*() calls with subprocess.run() using a list of arguments, which is more secure, more portable, and better maintained.
- 2Use absolute paths for executables instead of relying on PATH search to prevent executable hijacking via PATH manipulation.
- 3Validate all input that becomes an argument to any process-spawning call against a strict allowlist before use.
- 4Set explicit timeouts on subprocess.run() to prevent resource exhaustion from long-running or hung child processes.
- 5Capture stdout and stderr from spawned processes to prevent information leakage through process output.
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
This rule detects calls to os.spawnl(), os.spawnle(), os.spawnlp(), os.spawnlpe(), os.spawnv(), os.spawnve(), os.spawnvp(), and os.spawnvpe() from the Python os module. All variants are flagged since the spawn API is deprecated and all variants can execute arbitrary programs when given untrusted arguments.
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
Dangerous os.system() or os.popen() Call
os.system() and os.popen() execute shell commands via /bin/sh, enabling command injection when arguments contain untrusted input.
Dangerous os.exec*() Call
os.exec*() replaces the current process image with a new program, enabling arbitrary program execution when arguments are untrusted.
Dangerous subprocess Usage
subprocess calls detected. Ensure command arguments are not user-controlled to prevent OS command injection.
Frequently Asked Questions
Common questions about Dangerous os.spawn*() Call
New feature
Get these findings posted directly on your GitHub pull requests
The Dangerous os.spawn*() Call rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.