python.django.security.injection.code.user-eval-format-string.user-eval-format-string

profile photo of semgrepsemgrep
Author
9,069
Download Count*

Found user data in a call to 'eval'. This is extremely dangerous because it can enable an attacker to execute remote code. See https://owasp.org/www-community/attacks/Code_Injection for more information.

Run Locally

Run in CI

Defintion

rules:
  - id: user-eval-format-string
    message: Found user data in a call to 'eval'. This is extremely dangerous
      because it can enable an attacker to execute remote code. See
      https://owasp.org/www-community/attacks/Code_Injection for more
      information.
    metadata:
      cwe:
        - "CWE-95: Improper Neutralization of Directives in Dynamically
          Evaluated Code ('Eval Injection')"
      owasp:
        - A03:2021 - Injection
      references:
        - https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
      category: security
      technology:
        - django
      subcategory:
        - vuln
      likelihood: MEDIUM
      impact: HIGH
      confidence: MEDIUM
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Code Injection
    patterns:
      - pattern-inside: |
          def $F(...):
            ...
      - pattern-either:
          - pattern: eval(..., $STR % request.$W.get(...), ...)
          - pattern: |
              $V = request.$W.get(...)
              ...
              eval(..., $STR % $V, ...)
          - pattern: |
              $V = request.$W.get(...)
              ...
              $S = $STR % $V
              ...
              eval(..., $S, ...)
          - pattern: eval(..., "..." % request.$W(...), ...)
          - pattern: |
              $V = request.$W(...)
              ...
              eval(..., $STR % $V, ...)
          - pattern: |
              $V = request.$W(...)
              ...
              $S = $STR % $V
              ...
              eval(..., $S, ...)
          - pattern: eval(..., $STR % request.$W[...], ...)
          - pattern: |
              $V = request.$W[...]
              ...
              eval(..., $STR % $V, ...)
          - pattern: |
              $V = request.$W[...]
              ...
              $S = $STR % $V
              ...
              eval(..., $S, ...)
          - pattern: eval(..., $STR.format(..., request.$W.get(...), ...), ...)
          - pattern: |
              $V = request.$W.get(...)
              ...
              eval(..., $STR.format(..., $V, ...), ...)
          - pattern: |
              $V = request.$W.get(...)
              ...
              $S = $STR.format(..., $V, ...)
              ...
              eval(..., $S, ...)
          - pattern: eval(..., $STR.format(..., request.$W(...), ...), ...)
          - pattern: |
              $V = request.$W(...)
              ...
              eval(..., $STR.format(..., $V, ...), ...)
          - pattern: |
              $V = request.$W(...)
              ...
              $S = $STR.format(..., $V, ...)
              ...
              eval(..., $S, ...)
          - pattern: eval(..., $STR.format(..., request.$W[...], ...), ...)
          - pattern: |
              $V = request.$W[...]
              ...
              eval(..., $STR.format(..., $V, ...), ...)
          - pattern: |
              $V = request.$W[...]
              ...
              $S = $STR.format(..., $V, ...)
              ...
              eval(..., $S, ...)
          - pattern: |
              $V = request.$W.get(...)
              ...
              eval(..., f"...{$V}...", ...)
          - pattern: |
              $V = request.$W.get(...)
              ...
              $S = f"...{$V}..."
              ...
              eval(..., $S, ...)
          - pattern: |
              $V = request.$W(...)
              ...
              eval(..., f"...{$V}...", ...)
          - pattern: |
              $V = request.$W(...)
              ...
              $S = f"...{$V}..."
              ...
              eval(..., $S, ...)
          - pattern: |
              $V = request.$W[...]
              ...
              eval(..., f"...{$V}...", ...)
          - pattern: |
              $V = request.$W[...]
              ...
              $S = f"...{$V}..."
              ...
              eval(..., $S, ...)
    languages:
      - python
    severity: WARNING

Examples

user-eval-format-string.py

from textwrap import dedent

def unsafe(request):
    # ruleid: user-eval-format-string
    message = request.POST.get('message')
    print("do stuff here")
    code = """
    print(%s)
    """ % message
    eval(code)

def unsafe_inline(request):
    # ruleid: user-eval-format-string
    eval("print(%s)" % request.GET.get('message'))

def unsafe_dict(request):
    # ruleid: user-eval-format-string
    eval("print(%s)" % request.POST['message'])

def safe(request):
    # ok: user-eval-format-string
    code = """
    print('hello')
    """
    eval(dedent(code))

def fmt_unsafe(request):
    # ruleid: user-eval-format-string
    message = request.POST.get('message')
    print("do stuff here")
    code = """
    print({})
    """.format(message)
    eval(code)

def fmt_unsafe_inline(request):
    # ruleid: user-eval-format-string
    eval("print({})".format(request.GET.get('message')))

def fmt_unsafe_dict(request):
    # ruleid: user-eval-format-string
    eval("print({}, {})".format(request.POST['message'], "pwned"))

def fmt_safe(request):
    # ok: user-eval-format-string
    code = """
    print('hello')
    """
    eval(dedent(code))

def fstr_unsafe(request):
    # ruleid: user-eval-format-string
    message = request.POST.get('message')
    print("do stuff here")
    code = f"""
    print({message})
    """
    eval(code)

def fstr_unsafe_inline(request):
    # todoruleid: user-eval-format-string
    eval(f"print({request.GET.get('message')})")

def fstr_unsafe_dict(request):
    # todoruleid: user-eval-format-string
    eval(f"print({request.POST['message']})")

def fstr_safe(request):
    var = "hello"
    # ok: user-eval-format-string
    code = f"""
    print('{var}')
    """
    eval(dedent(code))