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-DJANGO-SEC-022 --project .About This Rule
Understanding the vulnerability and how it is detected
This rule detects code injection vulnerabilities in Django applications where untrusted user input from HTTP request parameters is used as a key to index the globals() dictionary for dynamic function dispatch.
Python's globals() returns the current module's global namespace as a dictionary. Using user-controlled input to retrieve entries from globals() (e.g., globals()[user_input]) and then calling the result allows an attacker to invoke any globally accessible callable, including imported functions, class constructors, and module-level objects. Depending on what is in scope, this can lead to OS command execution, file system access, database manipulation, or escalation to full code execution.
This pattern is sometimes used as an ad-hoc dispatch mechanism, but it exposes the entire global namespace to attackers. The correct approach is an explicit allowlist dictionary mapping safe string names to specific callable objects.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Unrestricted Function Dispatch
globals() exposes every name in the module's global scope: imported functions, class definitions, module references, and built-in references. An attacker can call os.system, subprocess.run, open, or any other global, not just the intended dispatch targets. The attack surface is the entire module namespace.
Imported Module Access
If the module imports os, subprocess, shutil, or other powerful modules, their functions are accessible through globals(). An attacker supplying os as the function name gets the entire os module, from which they can call os.system(), os.remove(), or os.environ to access any OS function.
Class Constructor Invocation
Model classes, form classes, and serializer classes are typically in scope. An attacker who invokes a class constructor via globals() with crafted arguments can create arbitrary model instances, potentially bypassing validation logic that is enforced at the view layer but not at the model constructor level.
Chained Code Execution via Callable Objects
Callable objects retrieved through globals() can be chained. If the attacker retrieves a partial or lambda that leads to a code path with further dynamic execution, the initial globals() access becomes the entry point for a more complex attack chain.
How to Fix
Recommended remediation steps
- 1Replace globals()[user_input] dispatch with an explicit dict mapping permitted string keys to specific callable objects.
- 2The allowlist dict should contain only the specific functions intended to be callable -- not entire modules or class hierarchies.
- 3Validate the action name is in the allowlist before attempting to call anything; return a 404 or 400 for unknown actions.
- 4Never expose the globals() or locals() namespace to user input, even indirectly through getattr() on modules.
- 5Audit all uses of getattr(module, user_input) for the same vulnerability pattern, as it is equivalent to globals()[user_input] for imported modules.
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
This rule performs inter-procedural taint analysis with global scope. Sources include calls("request.GET.get"), calls("request.POST.get"), calls("request.GET.__getitem__"), calls("request.POST.__getitem__"), calls("request.body"), and calls("request.read"). The sink is calls("globals") where the return value is indexed with a tainted key, tracked via .tracks(0). The rule also detects calls("getattr") where the attribute name argument is tainted (also equivalent to namespace traversal with user input). No sanitizers are recognized -- any user-controlled globals() indexing is flagged.
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
Django Code Injection via eval()
User input flows to eval(), enabling arbitrary Python code execution on the server.
Django Code Injection via exec()
User input flows to exec(), enabling arbitrary Python statement execution on the server.
Django Command Injection via os.system()
User input flows to os.system(), enabling arbitrary OS command execution with the privileges of the Django process.
Frequently Asked Questions
Common questions about Django globals() Misuse for Arbitrary Code Execution
New feature
Get these findings posted directly on your GitHub pull requests
The Django globals() Misuse for Arbitrary Code Execution rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.