python.lang.security.audit.non-literal-import.non-literal-import

profile photo of semgrepsemgrep
Author
1,200
Download Count*

Untrusted user input in importlib.import_module() function allows an attacker to load arbitrary code. Avoid dynamic values in importlib.import_module() or use a whitelist to prevent running untrusted code.

Run Locally

Run in CI

Defintion

rules:
  - id: non-literal-import
    patterns:
      - pattern: |
          importlib.import_module($NAME, ...)
      - pattern-not: |
          importlib.import_module("...", ...)
    message: Untrusted user input in `importlib.import_module()` function allows an
      attacker to load arbitrary code. Avoid dynamic values in
      `importlib.import_module()` or use a whitelist to prevent running
      untrusted code.
    metadata:
      owasp:
        - A01:2021 - Broken Access Control
      cwe:
        - "CWE-706: Use of Incorrectly-Resolved Name or Reference"
      category: security
      technology:
        - python
      references:
        - https://owasp.org/Top10/A01_2021-Broken_Access_Control
      subcategory:
        - audit
      likelihood: LOW
      impact: MEDIUM
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Improper Authorization
    languages:
      - python
    severity: WARNING

Examples

non-literal-import.py

import importlib
from werkzeug.datastructures import FileStorage
from pathlib import Path
import shutil

def run_payload(file_upload: FileStorage, import_name: str) -> None:
    if ".." in file_upload.filename or "/" in file_upload.filename:
        raise Exception(
            "Path traversal attempt. '..' and '/' not allowed in file name"
        )

    temp_folder = Path(__file__).parent.parent / "tmp"
    temp_folder.mkdir()
    temp_file = temp_folder / file_upload.filename

    file_upload.save(temp_file)

    try:
        # ruleid: non-literal-import
        importlib.import_module(import_name)

        # Do stuff
    finally:
        shutil.rmtree(str(temp_folder))

def ok():
    # ok: non-literal-import
    importlib.import_module("foobar")
    foobar()