python.lang.security.audit.dangerous-asyncio-exec.dangerous-asyncio-exec

Author
1,200
Download Count*
License
Detected subprocess function '$LOOP.subprocess_exec' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.
Run Locally
Run in CI
Defintion
rules:
- id: dangerous-asyncio-exec
pattern-either:
- patterns:
- pattern-not: $LOOP.subprocess_exec($PROTOCOL, "...", ...)
- pattern-not: $LOOP.subprocess_exec($PROTOCOL, ["...",...], ...)
- pattern: $LOOP.subprocess_exec(...)
- patterns:
- pattern-not: $LOOP.subprocess_exec($PROTOCOL, "=~/(sh|bash|ksh|csh|tcsh|zsh)/",
"-c", "...", ...)
- pattern: $LOOP.subprocess_exec($PROTOCOL, "=~/(sh|bash|ksh|csh|tcsh|zsh)/",
"-c",...)
- patterns:
- pattern-not: $LOOP.subprocess_exec($PROTOCOL, ["=~/(sh|bash|ksh|csh|tcsh|zsh)/",
"-c", "...", ...], ...)
- pattern: $LOOP.subprocess_exec($PROTOCOL, ["=~/(sh|bash|ksh|csh|tcsh|zsh)/",
"-c", ...], ...)
message: Detected subprocess function '$LOOP.subprocess_exec' without a static
string. If this data can be controlled by a malicious actor, it may be an
instance of command injection. Audit the use of this call to ensure it is
not controllable by an external resource. You may consider using
'shlex.escape()'.
metadata:
owasp: "A1: Injection"
cwe: "CWE-78: Improper Neutralization of Special Elements used in an OS Command
('OS Command Injection')"
asvs:
section: "V5: Validation, Sanitization and Encoding Verification Requirements"
control_id: 5.3.8 OS Command Injection
control_url: https://github.com/OWASP/ASVS/blob/master/4.0/en/0x13-V5-Validation-Sanitization-Encoding.md#v53-output-encoding-and-injection-prevention-requirements
version: "4"
references:
- https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.subprocess_exec
- https://docs.python.org/3/library/shlex.html
category: security
technology:
- python
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
languages:
- python
severity: ERROR
Examples
dangerous-asyncio-exec.py
import asyncio
class AsyncEventLoop:
def __enter__(self):
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
return self.loop
def __exit__(self, *args):
self.loop.close()
class WaitingProtocol(asyncio.SubprocessProtocol):
def __init__(self, exit_future):
self.exit_future = exit_future
def process_exited(self):
self.exit_future.set_result(True)
def vuln1():
args = get_user_input()
with AsyncEventLoop() as loop:
exit_future = asyncio.Future(loop=loop)
# ruleid: dangerous-asyncio-exec
transport, _ = loop.run_until_complete(loop.subprocess_exec(lambda: WaitingProtocol(exit_future), *args))
loop.run_until_complete(exit_future)
transport.close()
def vuln2():
loop = asyncio.new_event_loop()
exit_future = asyncio.Future(loop=loop)
# ruleid: dangerous-asyncio-exec
transport, _ = loop.run_until_complete(loop.subprocess_exec(lambda: WaitingProtocol(exit_future), ["bash", "-c", sys.argv[1]]))
loop.run_until_complete(exit_future)
transport.close()
def ok1():
loop = asyncio.new_event_loop()
exit_future = asyncio.Future(loop=loop)
# ok: dangerous-asyncio-exec
transport, _ = loop.run_until_complete(loop.subprocess_exec(lambda: WaitingProtocol(exit_future), ["echo", "a"]))
loop.run_until_complete(exit_future)
transport.close()
Short Link: https://sg.run/lxjy