eval and exec execute arbitrary Python code; they cannot be safely sandboxed
eval() parses and executes a Python expression, and exec() executes a block of Python statements. Both run the input as code with the full privileges of the process. If the input comes from a user, a network request, a config file, or any untrusted source, an attacker can read files, open sockets, import modules, or call os.system. The danger is not limited to obviously malicious strings; even expressions that look safe can reach builtins through attribute access. Attempts to sandbox eval by passing a restricted globals dict are well known to be bypassable, because Python's object graph exposes builtins through many paths. The correct approach is to never eval untrusted input. For simple literals use ast.literal_eval, which parses only Python literals and raises on anything else. For structured data use json or a schema-validated parser. For expression languages use a dedicated library such as asteval or a formula parser rather than Python itself.
eval and exec run code with the process's privileges. There is no supported sandbox in CPython.
Restricted globals and builtins tricks are bypassable. Do not rely on them.
ast.literal_eval is safe for strings, numbers, tuples, lists, dicts, sets, booleans, and None. It does not evaluate expressions.
Common injection surfaces: calculator features, config expressions, template engines, and rules engines that accept user formulas.
Trade-off: a real expression language adds a dependency and a learning curve, but it is the only safe option for untrusted dynamic logic.
Common mistake: believing that removing builtins from the globals dict makes eval safe. It does not.
Common mistake: using eval for simple type conversion, such as eval('123'), when int() would be safer and clearer.
Version note: ast.literal_eval has been in the stdlib since Python 2.6 and its safety guarantees are stable across Python 3.
0-2 years experience
2-5 years experience
5-8 years experience
8+ years experience