Dangerous exec() Usage Detected

HIGH

exec() executes arbitrary Python statements from strings or code objects, enabling remote code execution when called with untrusted input.

Rule Information

Language
Python
Category
Python Core
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonexeccode-injectiondynamic-executionbuiltinsCWE-95OWASP-A03
CWE References

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-002 --project .
1
2
3
4
5
6
7
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

About This Rule

Understanding the vulnerability and how it is detected

Python's built-in exec() function executes dynamically constructed Python code including full statements, class and function definitions, import statements, and control flow. Unlike eval(), exec() is not restricted to expressions and can execute any valid Python code, making it significantly more dangerous.

When exec() receives a string derived from untrusted input such as HTTP parameters, file contents, environment variables, or inter-process messages, an attacker can inject arbitrary Python statements that spawn shells, exfiltrate data, install backdoors, modify the global state of the application, or execute any OS command on the host system.

There is no safe way to sandbox exec() using restricted namespace dictionaries — Python's introspection capabilities have been used to escape all known namespace-based sandboxes. The correct fix is always to avoid exec() on untrusted input entirely.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Full Remote Code Execution

exec() can execute any valid Python statement, giving an attacker complete control over the process. This includes defining functions, spawning threads, importing modules, modifying global variables, and executing OS commands via os.system() or subprocess.

2

Application State Corruption

exec() can redefine functions, classes, and module-level variables at runtime. An attacker injecting code via exec() can replace authentication logic, disable security checks, or corrupt application state in ways that persist for the lifetime of the process.

3

Namespace Sandbox Escape

Attempts to restrict exec() by passing custom globals/locals dictionaries are insufficient. Python's __subclasses__(), __mro__, and __builtins__ attributes provide paths to escape any namespace restriction that has been attempted in practice.

4

Persistence and Lateral Movement

Through exec(), an attacker can write files to disk, modify installed packages, schedule cron jobs, and open persistent reverse shell connections that survive beyond the current request or session.

How to Fix

Recommended remediation steps

  • 1Never pass user-controlled strings to exec(); there is no safe way to sandbox exec() on arbitrary input.
  • 2Replace exec()-based plugin systems with importlib.import_module() restricted to an allowlist of module names.
  • 3Use getattr() with explicit allowlists for dynamic method dispatch instead of constructing and exec()-ing code strings.
  • 4If code generation is genuinely required, generate code at build time (not runtime) from trusted templates with no user-controlled content.
  • 5Apply process isolation such as containers or separate processes with minimal privileges to limit the blast radius of any exec() exploitation.

Detection Scope

How Code Pathfinder analyzes your code for this vulnerability

This rule detects all direct calls to the built-in exec() function anywhere in Python source code, matching both unqualified exec() and builtins.exec() forms. The rule flags every call site since exec() on any dynamically constructed string is a security concern regardless of the apparent origin of the string.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

CWE Top 25
CWE-95 - Eval Injection in the MITRE CWE Top 25 Most Dangerous Software Weaknesses
OWASP Top 10
A03:2021 - Injection
NIST SP 800-53
SI-10: Information Input Validation
PCI DSS v4.0
Requirement 6.2.4 - Protect web-facing applications against injection attacks

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about Dangerous exec() Usage Detected

Yes. eval() is restricted to single expressions while exec() can execute any valid Python code including import statements, function definitions, class definitions, and multi-line programs. exec() is essentially a full Python interpreter invocation on an arbitrary string.
No. Namespace-based sandboxes for exec() have been broken repeatedly. Python's introspection features such as __subclasses__(), object.__mro__, and __builtins__ provide multiple escape paths from any namespace restriction. Treat exec() on untrusted input as unconditionally exploitable.
Use importlib.import_module() with a strict allowlist of permitted module names for plugin systems. Use getattr() with allowlists for dynamic method dispatch. Use ast.literal_eval() for data parsing. Use template engines for code generation that runs at build time rather than runtime.
Yes. The rule flags all exec() call sites. Build tools that use exec() on trusted, version-controlled code files are generally safe, but should be reviewed to ensure no user-controlled data can influence the executed string. Document suppressed findings with a clear explanation of the trust boundary.
In a Jupyter notebook or interactive shell, exec() is less risky because the user already has code execution. However, any server-side component that uses exec() to execute notebook cell content received from a client is critically dangerous and should use a proper sandboxed execution environment instead.
The rule performs both pattern-based detection of all exec() calls and taint-aware analysis that traces data flow from HTTP request parameters, os.environ, file reads, and network input through variable assignments across function boundaries to the exec() call site. Tainted flows are reported with higher severity.

New feature

Get these findings posted directly on your GitHub pull requests

The Dangerous exec() Usage Detected rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works