python.django.security.injection.code.user-exec.user-exec

Verifed by r2c
Community Favorite
profile photo of semgrepsemgrep
Author
100,049
Download Count*

Found user data in a call to 'exec'. This is extremely dangerous because it can enable an attacker to execute arbitrary remote code on the system. Instead, refactor your code to not use 'eval' and instead use a safe library for the specific functionality you need.

Run Locally

Run in CI

Defintion

rules:
  - id: user-exec
    message: Found user data in a call to 'exec'. This is extremely dangerous
      because it can enable an attacker to execute arbitrary remote code on the
      system. Instead, refactor your code to not use 'eval' and instead use a
      safe library for the specific functionality you need.
    metadata:
      cwe:
        - "CWE-95: Improper Neutralization of Directives in Dynamically
          Evaluated Code ('Eval Injection')"
      owasp:
        - A03:2021 - Injection
      category: security
      technology:
        - django
      references:
        - https://owasp.org/www-community/attacks/Code_Injection
      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: exec(..., request.$W.get(...), ...)
          - pattern: |
              $V = request.$W.get(...)
              ...
              exec(..., $V, ...)
          - pattern: exec(..., request.$W(...), ...)
          - pattern: |
              $V = request.$W(...)
              ...
              exec(..., $V, ...)
          - pattern: exec(..., request.$W[...], ...)
          - pattern: |
              $V = request.$W[...]
              ...
              exec(..., $V, ...)
          - pattern: |
              loop = asyncio.get_running_loop()
              ...
              await loop.run_in_executor(None, exec, request.$W[...])
          - pattern: |
              $V = request.$W[...]
              ...
              loop = asyncio.get_running_loop()
              ...
              await loop.run_in_executor(None, exec, $V)
          - pattern: |
              loop = asyncio.get_running_loop()
              ...
              await loop.run_in_executor(None, exec, request.$W.get(...))
          - pattern: |
              $V = request.$W.get(...)
              ...
              loop = asyncio.get_running_loop()
              ...
              await loop.run_in_executor(None, exec, $V)
    languages:
      - python
    severity: WARNING

Examples

user-exec.py

import asyncio
from textwrap import dedent

def unsafe(request):
    # ruleid: user-exec
    code = request.POST.get('code')
    print("something")
    exec(code)

def unsafe_inline(request):
    # ruleid: user-exec
    exec(request.GET.get('code'))

def unsafe_dict(request):
    # ruleid: user-exec
    exec(request.POST['code'])

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

async def run_exec_inline_get_method_by_event_loop(request):
    # ruleid: user-exec
    loop = asyncio.get_running_loop()
    await loop.run_in_executor(None, exec, request.POST.get("code"))

async def run_exec_inline_dict_by_event_loop(request):
    # ruleid: user-exec
    loop = asyncio.get_running_loop()
    await loop.run_in_executor(None, exec, request.POST["code"])

async def run_exec_by_get_method_event_loop(request):
    # ruleid: user-exec
    code = request.POST.get("code")
    loop = asyncio.get_running_loop()
    await loop.run_in_executor(None, exec, code)

async def run_exec_by_event_loop(request):
    # ruleid: user-exec
    code = request.POST["code"]
    loop = asyncio.get_running_loop()
    await loop.run_in_executor(None, exec, code)