03 / 05

Why is using eval() or exec() on untrusted input a serious security risk?

Difficulty: 6/10
Eval, Exec, Arbitrary Code Execution, Literal Eval

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.

  1. 1

    eval and exec run code with the process's privileges. There is no supported sandbox in CPython.

  2. 2

    Restricted globals and builtins tricks are bypassable. Do not rely on them.

  3. 3

    ast.literal_eval is safe for strings, numbers, tuples, lists, dicts, sets, booleans, and None. It does not evaluate expressions.

  4. 4

    Common injection surfaces: calculator features, config expressions, template engines, and rules engines that accept user formulas.

  5. 5

    Trade-off: a real expression language adds a dependency and a learning curve, but it is the only safe option for untrusted dynamic logic.

  6. 6

    Common mistake: believing that removing builtins from the globals dict makes eval safe. It does not.

  7. 7

    Common mistake: using eval for simple type conversion, such as eval('123'), when int() would be safer and clearer.

  8. 8

    Version note: ast.literal_eval has been in the stdlib since Python 2.6 and its safety guarantees are stable across Python 3.

javascript

Scenario Questions

0-2 years experience

  1. 1You need to convert a string like '[1, 2, 3]' into a list. Which function is safe?
  2. 2Why is eval('1+1') dangerous if the input comes from a user?

2-5 years experience

  1. 1A feature lets users write simple arithmetic rules. How would you implement it without eval?
  2. 2You see eval used with a restricted globals dict in legacy code. How do you assess the risk and replace it?

5-8 years experience

  1. 1You need a config format that supports expressions evaluated at runtime. How do you design it safely?
  2. 2A third-party library you depend on uses eval internally on user data. How do you evaluate and mitigate the risk?

8+ years experience

  1. 1Design a rules engine that supports user-defined conditions and actions without ever executing Python code from users, and explain how you enforce that in CI.
  2. 2Compare ast.literal_eval, asteval, and a custom parser on safety, expressiveness, and maintenance cost for a product feature.

Follow-up Questions

  • Why is ast.literal_eval safe while eval is not?
  • What is a safe way to implement a user-defined formula feature?
Share

Share via WhatsApp, X, Facebook, LinkedIn or copy link. Open Graph preview enabled.