Sitemap
Python in Plain English

New Python content every day. Follow to join our 3.5M+ monthly readers.

Exploring eval Dynamic Code Execution in Python

Understand the power and risks of Python’s eval() function and safer options

6 min readNov 11, 2024

--

Press enter or click to view image in full size
Image made by me , feel free to join my LinkedIn group here

The eval() function in Python is powerful—it allows you to execute Python expressions stored in strings, which can unlock a lot of flexibility in your code. However, because eval() executes any code within a string, it also comes with significant security risks. Improper use of eval() can lead to vulnerabilities, particularly if it’s used on untrusted inputs.

Hi, my name is CyCoderX and in this article, we’ll explore what eval() does, how to use it effectively, and, most importantly, how to use it safely. We’ll walk through examples, discuss when it’s appropriate to use eval(), and examine safer alternatives.

Let’s dive in!

I write articles for everyone to enjoy, and I’d love your support by following me for more Python, SQL, Data Engineering and Data Science content.😊

Understanding eval(): What It Does

The eval() function in Python takes a string as input, evaluates it as a Python expression, and returns the result. This can be particularly useful for dynamically executing code or processing user inputs. Here’s a quick look at its syntax:

eval(expression, globals=None, locals=None)
  • expression: A string containing a Python expression to evaluate.
  • globals and locals: Optional parameters to define the global and local namespaces in which the expression should run.

Basic Example

expression = "3 + 4"
result = eval(expression)
print(result) # Output: 7

Here, eval() evaluates the string as a Python expression and returns the result of 3 + 4, which is 7.

Using eval() with Variables

You can use eval() to evaluate expressions that involve variables, making it even more flexible. When using eval() in this way, you can define which variables are accessible within the expression by specifying the globals and locals dictionaries.

Example: Using Variables with eval()

x = 10
y = 5
expression = "x * y"
result = eval(expression)
print(result) # Output: 50

Example: Custom Namespace with globals and locals

Using globals and locals lets you limit the variables available to the expression. For example:

x = 10
namespace = {"x": x, "y": 2}
expression = "x + y"
result = eval(expression, {}, namespace)
print(result) # Output: 12

Here, y is defined only within the namespace dictionary, so it’s accessible to eval() but not part of the global scope.

The Dangers of eval()

While eval() can be very useful, it is also one of the most dangerous functions in Python due to the security risks associated with executing arbitrary code. If eval() is used on untrusted input, it opens the door to potential security issues, such as code injection attacks.

Example of a Security Risk

If you allow users to enter a string to evaluate, they could enter a harmful expression that could delete files, access sensitive information, or cause other damage.

user_input = "__import__('os').system('rm -rf /')"  # # # This is dangerous!
# # # result = eval(user_input) # DO NOT RUN THIS!

In this example, a malicious user could delete files on the system if eval() is used on unchecked input. This is why you should never use eval() with data from untrusted sources.

Press enter or click to view image in full size
Photo by moren hsu on Unsplash

Safe Ways to Use eval()

If you decide to use eval(), there are a few ways to minimize the risks, especially when working with user inputs. Here are some strategies to use eval() more securely:

  • Restrict the Global and Local Namespaces: Use the globals and locals parameters to control which variables and functions are accessible within eval().
  • Pre-define Allowed Variables: Limit eval() to work with only certain variables or functions to ensure it can’t access sensitive data.

Example: Limiting Access to a Custom Namespace

In this example, we restrict eval() to a namespace that contains only the variables x and y, reducing the risk of unauthorized access:

x = 10
y = 20
namespace = {"x": x, "y": y} # Only allow access to x and y
expression = "x + y"
result = eval(expression, {"__builtins__": None}, namespace)
print(result) # Output: 30

Setting __builtins__ to None removes access to built-in functions like open() or exec(), which enhances security.

When to Use eval() and When to Avoid It

Knowing when to use eval() is crucial. Although eval() is powerful, it is rarely essential. Here are some scenarios where eval() might be acceptable and situations where it’s best avoided.

When eval() Can Be Useful:

  • Mathematical Expression Evaluation: If your application requires evaluating mathematical expressions dynamically.
  • Simple Data Parsing: If you’re working with trusted, pre-defined expressions that need evaluating as part of data processing.

When to Avoid eval():

  • User-Generated Content: If users provide input to be evaluated, avoid eval() or sanitize inputs thoroughly.
  • Alternative Solutions: Look for safer alternatives (e.g., using ast.literal_eval() for evaluating literals).

In general, if there’s a way to achieve your goal without eval(), consider using it, as it will usually be safer and more maintainable.

Safer Alternatives to eval()

Python offers safer alternatives that provide similar functionality without the security risks. One of the most common alternatives is ast.literal_eval(), which evaluates expressions containing only Python literals, like numbers, strings, tuples, lists, dictionaries, and booleans.

Using ast.literal_eval() for Safer Evaluation

To safely evaluate literals, use ast.literal_eval(). Unlike eval(), it doesn’t allow arbitrary code execution, making it a safer choice for many applications.

import ast

expression = "{'name': 'Alice', 'age': 30}"
result = ast.literal_eval(expression)
print(result) # Output: {'name': 'Alice', 'age': 30}

In this example, ast.literal_eval() can parse a string representation of a dictionary without the risk of executing unwanted code.

Conclusion

The eval() function in Python offers significant flexibility, allowing for the dynamic evaluation of expressions. However, with this flexibility comes a responsibility to ensure secure usage.

Get CyCoderX’s stories in your inbox

Join Medium for free to get updates from this writer.

By understanding the potential risks, using restricted namespaces, and opting for safer alternatives like ast.literal_eval() where possible, you can harness eval() effectively while keeping your code secure. As a best practice, always consider if eval() is truly necessary, and explore safer options before relying on it.

Happy Coding!

Always conduct your own research and verify online information. Relying on others can lead to outdated practices, so take the initiative to implement and refine code to suit your needs. Note that I am not sponsored or affiliated with any services or products mentioned; my advice comes from my own experiences.

Press enter or click to view image in full size
Photo by Markus Spiske on Unsplash

Final Words:

Thank you for taking the time to read my article.
This article was first published on Medium by CyCoderX.

Hi, I’m CyCoderX! I’m a data engineer passionate about sharing knowledge, I write articles about Python, SQL, Data Science, Data Engineering, lifestyle and more!

What did you think about this article? Let me know in the comments below … or above, depending on your device!

In Plain English 🚀

Thank you for being a part of the In Plain English community! Before you go:

--

--

CyCoderX
CyCoderX

Written by CyCoderX

Machine Learning & Data Engineer | Data Science | Python & SQL | AI | Software Developer | Azure & AWS Cloud Specialist | Blogger simplifying Big Data & Trends

Python in Plain English
Python in Plain English

Published in Python in Plain English

New Python content every day. Follow to join our 3.5M+ monthly readers.