Interactive Playground
Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.
pathfinder scan --ruleset python/PYTHON-LANG-SEC-005 --project .About This Rule
Understanding the vulnerability and how it is detected
Python's __import__() built-in and importlib.import_module() allow modules to be loaded by name at runtime. When the module name argument is derived from untrusted external input such as HTTP parameters, configuration files, or user-provided data, an attacker can import malicious modules, access sensitive built-in modules such as os or subprocess, or perform path traversal to load modules from unexpected filesystem locations.
Common vulnerable patterns include plugin systems that load user-specified modules by name, serialization systems that reconstruct classes using stored module paths, and configuration- driven dispatch tables that resolve handler names from external data.
The fix is always to validate the module name against an explicit allowlist of permitted module names before calling import_module(), ensuring no user-controlled value can cause an unexpected module to be loaded.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Arbitrary Module Execution
An attacker who controls the module name can import os, subprocess, socket, or any other standard library module and immediately call dangerous functions on it. Module-level code is executed on import, so importing a malicious module can trigger code execution before any function is called.
Plugin System Exploitation
Plugin systems using import_module() to load user-specified plugins are vulnerable to loading attacker-controlled modules from the Python path. If the attacker can place a file on the server or influence sys.path, they can execute arbitrary code through the plugin loader.
Pickle-like Class Reconstruction Attacks
Serialization formats that store class locations as module:classname strings and use import_module() to reconstruct them are vulnerable to the same class of attacks as pickle deserialization. An attacker who controls the stored class location can cause any callable to be invoked during deserialization.
Path Traversal to Sensitive Modules
Depending on sys.path configuration, an attacker may be able to use relative module names or dotted paths to traverse to modules outside the intended plugin directory, potentially loading internal utility modules that expose sensitive operations.
How to Fix
Recommended remediation steps
- 1Always validate the module name against an explicit allowlist before calling import_module() or __import__().
- 2Prefer a static import registry (dict mapping names to already-imported classes) over dynamic imports to avoid the risk entirely.
- 3Restrict plugin directories and sys.path to prevent loading of modules outside the intended scope.
- 4Use __import__() only with hardcoded string literals; use importlib.import_module() for dynamic imports with proper validation.
- 5Log all dynamic module imports with the caller context to detect attempts to load unauthorized modules.
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
This rule detects calls to __import__() and importlib.import_module() where the module name argument is not a string literal. It flags all such calls since the module name may be influenced by external input at runtime. Calls with hardcoded string literals are considered lower risk but are still flagged for review.
Compliance & Standards
Industry frameworks and regulations that require detection of this vulnerability
References
External resources and documentation
Similar Rules
Explore related security rules for Python
Dangerous eval() Usage Detected
eval() executes arbitrary Python expressions from strings, enabling remote code execution when called with untrusted input.
Dangerous exec() Usage Detected
exec() executes arbitrary Python statements from strings or code objects, enabling remote code execution when called with untrusted input.
Dangerous globals() Usage Detected
globals() exposes the module's global namespace as a mutable dictionary, allowing arbitrary attribute injection when passed to untrusted code.
Frequently Asked Questions
Common questions about Non-literal Dynamic Import Detected
New feature
Get these findings posted directly on your GitHub pull requests
The Non-literal Dynamic Import Detected rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.