Implement command injection example in Flask app#2
Conversation
Added a Flask route that executes a command using os.execl.
| def route_param(route_param): | ||
|
|
||
| # ruleid:dangerous-os-exec | ||
| os.execl("/bin/bash", "/bin/bash", "-c", route_param) |
There was a problem hiding this comment.
Semgrep identified an issue in your code:
User-controlled Flask route parameter passed directly to shell command execution via os.execl(). Attackers can execute arbitrary commands by crafting malicious URL paths.
More details about this
The route_param variable from the Flask route is passed directly as a command to os.execl(), allowing arbitrary shell command execution.
Here's how an attacker could exploit this:
- An attacker crafts a malicious URL like
http://yourapp.com/route_param/$(rm%20-rf%20/)orhttp://yourapp.com/route_param/;%20cat%20/etc/passwd - Flask captures this URL path parameter as
route_param - The
route_paramvalue is passed unsanitized toos.execl("/bin/bash", "/bin/bash", "-c", route_param), where the-cflag tells bash to execute the string as a command - The shell interprets the attacker's payload (like
$(rm -rf /)or; cat /etc/passwd) as actual commands and executes them with the same privileges as the Python process - The attacker gains the ability to read files, delete data, modify system state, or pivot to other systems depending on what permissions the application has
Dataflow graph
flowchart LR
classDef invis fill:white, stroke: none
classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none
subgraph File0["<b>vulns/command_inject.py</b>"]
direction LR
%% Source
subgraph Source
direction LR
v0["<a href=https://github.com/SophiaManicor/bad-python-app/blob/f9b8a4ba1ca76fae0e0546fd48a433a3ebba1f90/vulns/command_inject.py#L8 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 8] route_param</a>"]
end
%% Intermediate
subgraph Traces0[Traces]
direction TB
v2["<a href=https://github.com/SophiaManicor/bad-python-app/blob/f9b8a4ba1ca76fae0e0546fd48a433a3ebba1f90/vulns/command_inject.py#L8 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 8] route_param</a>"]
end
%% Sink
subgraph Sink
direction LR
v1["<a href=https://github.com/SophiaManicor/bad-python-app/blob/f9b8a4ba1ca76fae0e0546fd48a433a3ebba1f90/vulns/command_inject.py#L11 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 11] route_param</a>"]
end
end
%% Class Assignment
Source:::invis
Sink:::invis
Traces0:::invis
File0:::invis
%% Connections
Source --> Traces0
Traces0 --> Sink
To resolve this comment:
✨ Commit Assistant fix suggestion
| os.execl("/bin/bash", "/bin/bash", "-c", route_param) | |
| # Define a whitelist of allowed commands to prevent command injection | |
| allowed_commands = {"ls", "whoami"} # Add only safe commands needed by your app | |
| if route_param in allowed_commands: | |
| os.execl("/bin/bash", "/bin/bash", "-c", route_param) | |
| else: | |
| # Reject disallowed input | |
| return "Invalid command", 400 |
View step-by-step instructions
- Never pass user input (such as
route_param) directly toos.execlwith-c, as this allows an attacker to execute arbitrary shell commands. - If you need to execute only specific known commands, define a whitelist of allowed commands in your code. For example:
allowed_commands = {"ls", "whoami"}. - Before calling
os.execl, check thatroute_paramis in your whitelist:if route_param in allowed_commands:. If it is not, reject the input or return an error. - Alternatively, if possible, avoid using shell commands altogether. Use built-in Python functions to achieve the desired effect rather than calling out to the shell.
- If you absolutely must pass user data to a subprocess, never use shell mode or
-c. Instead, use a function such assubprocess.run([<command>, <args>], shell=False)and pass only trusted list elements, not shell strings.
By strictly controlling what commands can be executed, you prevent attackers from injecting malicious input that could compromise your server.
💬 Ignore this finding
Reply with Semgrep commands to ignore this finding.
/fp <comment>for false positive/ar <comment>for acceptable risk/other <comment>for all other reasons
Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by dangerous-os-exec.
You can view more details about this finding in the Semgrep AppSec Platform.
Added a Flask route that executes a command using os.execl.