python.lang.security.audit.dangerous-code-run-tainted-env-args.dangerous-interactive-code-run-tainted-env-args

profile photo of semgrepsemgrep
Author
unknown
Download Count*

Found user controlled data inside InteractiveConsole/InteractiveInterpreter method. This is dangerous if external data can reach this function call because it allows a malicious actor to run arbitrary Python code.

Run Locally

Run in CI

Defintion

rules:
  - id: dangerous-interactive-code-run-tainted-env-args
    mode: taint
    options:
      symbolic_propagation: true
    pattern-sources:
      - patterns:
          - pattern-either:
              - patterns:
                  - pattern-either:
                      - pattern: os.environ
                      - pattern: os.environ.get('$FOO', ...)
                      - pattern: os.environb
                      - pattern: os.environb.get('$FOO', ...)
                      - pattern: os.getenv('$ANYTHING', ...)
                      - pattern: os.getenvb('$ANYTHING', ...)
              - patterns:
                  - pattern-either:
                      - patterns:
                          - pattern-either:
                              - pattern: sys.argv
                              - pattern: sys.orig_argv
                      - patterns:
                          - pattern-inside: |
                              $PARSER = argparse.ArgumentParser(...)
                              ...
                          - pattern-inside: |
                              $ARGS = $PARSER.parse_args()
                          - pattern: <... $ARGS ...>
                      - patterns:
                          - pattern-inside: |
                              $PARSER = optparse.OptionParser(...)
                              ...
                          - pattern-inside: |
                              $ARGS = $PARSER.parse_args()
                          - pattern: <... $ARGS ...>
                      - patterns:
                          - pattern-either:
                              - pattern-inside: |
                                  $OPTS, $ARGS = getopt.getopt(...)
                                  ...
                              - pattern-inside: |
                                  $OPTS, $ARGS = getopt.gnu_getopt(...)
                                  ...
                          - pattern-either:
                              - patterns:
                                  - pattern-inside: |
                                      for $O, $A in $OPTS:
                                        ...
                                  - pattern: $A
                              - pattern: $ARGS
    pattern-sinks:
      - patterns:
          - pattern-either:
              - pattern-inside: |
                  $X = code.InteractiveConsole(...)
                  ...
              - pattern-inside: |
                  $X = code.InteractiveInterpreter(...)
                  ...
          - pattern-either:
              - pattern-inside: |
                  $X.push($PAYLOAD,...)
              - pattern-inside: |
                  $X.runsource($PAYLOAD,...)
              - pattern-inside: |
                  $X.runcode(code.compile_command($PAYLOAD),...)
              - pattern-inside: |
                  $PL = code.compile_command($PAYLOAD,...)
                  ...
                  $X.runcode($PL,...)
          - pattern: $PAYLOAD
          - pattern-not: |
              $X.push("...",...)
          - pattern-not: |
              $X.runsource("...",...)
          - pattern-not: |
              $X.runcode(code.compile_command("..."),...)
          - pattern-not: |
              $PL = code.compile_command("...",...)
              ...
              $X.runcode($PL,...)
    message: Found user controlled data inside
      InteractiveConsole/InteractiveInterpreter method. This is dangerous if
      external data can reach this function call because it allows a malicious
      actor to run arbitrary Python code.
    metadata:
      cwe:
        - "CWE-95: Improper Neutralization of Directives in Dynamically
          Evaluated Code ('Eval Injection')"
      owasp:
        - A03:2021 - Injection
      references:
        - https://semgrep.dev/docs/cheat-sheets/python-command-injection/
      category: security
      technology:
        - python
      confidence: MEDIUM
      subcategory:
        - vuln
      likelihood: MEDIUM
      impact: HIGH
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Code Injection
    severity: WARNING
    languages:
      - python

Examples

dangerous-code-run-tainted-env-args.py

import code
import sys


def run_payload0() -> None:
    payload = sys.argv[2]
    console = code.InteractiveConsole()
    # ruleid: dangerous-interactive-code-run-tainted-env-args
    console.push(payload)


def run_payload1(payload: str) -> None:
    console = code.InteractiveConsole()
    # fn: dangerous-interactive-code-run-tainted-env-args
    console.push(payload)


def run_payload2(payload: str) -> None:
    inperpreter = code.InteractiveInterpreter()
    # fn: dangerous-interactive-code-run-tainted-env-args
    inperpreter.runcode(code.compile_command(payload))


def run_payload3(payload: str) -> None:
    inperpreter = code.InteractiveInterpreter()
    # fn: dangerous-interactive-code-run-tainted-env-args
    pl = code.compile_command(payload)
    inperpreter.runcode(pl)


def run_payload4(payload: str) -> None:
    inperpreter = code.InteractiveInterpreter()
    # fn: dangerous-interactive-code-run-tainted-env-args
    inperpreter.runsource(payload)


def ok1() -> None:
    console = code.InteractiveConsole()
    console.push("print(123)")


def ok2() -> None:
    inperpreter = code.InteractiveInterpreter()
    inperpreter.runcode(code.compile_command("print(123)"))


def ok3() -> None:
    inperpreter = code.InteractiveInterpreter()
    pl = code.compile_command("print(123)")
    inperpreter.runcode(pl)


def ok4() -> None:
    inperpreter = code.InteractiveInterpreter()
    inperpreter.runsource("print(123)")