Skip to content

Implement command injection example in Flask app#2

Open
SophiaManicor wants to merge 1 commit into
mainfrom
SophiaManicor-patch-1
Open

Implement command injection example in Flask app#2
SophiaManicor wants to merge 1 commit into
mainfrom
SophiaManicor-patch-1

Conversation

@SophiaManicor

Copy link
Copy Markdown
Owner

Added a Flask route that executes a command using os.execl.

Added a Flask route that executes a command using os.execl.
Comment thread vulns/command_inject.py
def route_param(route_param):

# ruleid:dangerous-os-exec
os.execl("/bin/bash", "/bin/bash", "-c", route_param)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. An attacker crafts a malicious URL like http://yourapp.com/route_param/$(rm%20-rf%20/) or http://yourapp.com/route_param/;%20cat%20/etc/passwd
  2. Flask captures this URL path parameter as route_param
  3. The route_param value is passed unsanitized to os.execl("/bin/bash", "/bin/bash", "-c", route_param), where the -c flag tells bash to execute the string as a command
  4. 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
  5. 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


Loading

To resolve this comment:

✨ Commit Assistant fix suggestion

Suggested change
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
  1. Never pass user input (such as route_param) directly to os.execl with -c, as this allows an attacker to execute arbitrary shell commands.
  2. If you need to execute only specific known commands, define a whitelist of allowed commands in your code. For example: allowed_commands = {"ls", "whoami"}.
  3. Before calling os.execl, check that route_param is in your whitelist: if route_param in allowed_commands:. If it is not, reject the input or return an error.
  4. 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.
  5. If you absolutely must pass user data to a subprocess, never use shell mode or -c. Instead, use a function such as subprocess.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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant