Python eval() Function
The eval()
method parses the expression passed to this method and runs python expression (code) within the program.
Syntax
eval(expression, globals=None, locals=None)
eval() Parameters
Python eval()
function parameters:
Parameter | Condition | Description |
---|---|---|
expression | Required | A String, that will be evaluated as Python code |
globals | Optional | A dictionary containing global parameters |
locals | Optional | A dictionary containing local parameters |
eval() Return Value
Python eval()
function returns the result evaluated from the expression.
Examples
Example 1: evaluating an arithmetic expression with eval() function
result = eval('1 + 2')
print(result) # Output: 3
output
3
Example 2: evaluating a complex expression involving a function call with eval() function
result = eval('sum([1, 2, 3, 4])')
print(result) # Output: 10
output
10
Example 3: evaluating a boolean expression with eval() function
result = eval('True and False')
print(result) # Output: False
output
False
Example 4: using eval() with custom global and local namespaces
def square(number):
return number * number
global_vars = {"square": square}
result = eval("square(5)", global_vars)
print(result) # Output: 25
output
25
Security issues of using eval() function and possible mitigations
Security issues of eval() function
The Python eval()
function can expose you to some security risks.
Consider a situation where you are using a Unix system (macOS, Linux, etc.) and you have imported the os
module. The os
module provides a portable way to use operating system functionalities like reading or writing to a file.
If you allow users to input a value using eval(input())
, the user may issue commands to change file or even delete all the files using the command: os.system('rm -rf *')
.
If you are using eval(input())
in your code, it is a good idea to check which variables and functions the user can use. You can see which variables and methods are available using dir()
function.
Mitigations of using eval() function
Frequently, not all methods and variables that are available within the scope of eval()
are required or even pose potential security threats. Therefore, it is often beneficial to limit the scope of these methods and variables for safety purposes.
To achieve this, you can provide the eval()
function with optional globals and locals parameters, which are dictionaries that define the global
and local
namespaces for the evaluated expression.
Restricting the use of eval()
by passing globals and locals dictionaries will make your code secure particularly when you are using input provided by the user to the eval()
method.
Sometimes, eval()
is not secure even with limited names. When an object and its methods are made accessible, almost anything can be done by an attacker. The only secure way is by validating the user input.
1. When both globals and locals parameters omitted
If both parameters are omitted (as in our earlier examples), the expression
is executed in the current scope. You can check the available variables and methods using following code:
print(eval('dir()')
2. Passing globals parameter and locals parameter is omitted
When using eval()
in Python, you can specify the global and local namespaces through the globals
and locals
parameters. If the locals
parameter is not provided, it defaults to the globals
dictionary, meaning that the global namespace will be used for both global and local variables within the evaluated expression.
For example, you can pass empty dictionary as globals parameter:
from math import *
print(eval('dir()', {}))
# The code will raise an exception
print(eval('sqrt(25)', {}))
output
['__builtins__']
Traceback (most recent call last):
File "main.py", line 5, in <module>
print(eval('sqrt(25)', {}))
File "<string>", line 1, in <module>
NameError: name 'sqrt' is not defined
If you pass an empty dictionary as globals, only the __builtins__
are available to expression (first parameter of the eval()
).
Even though we have imported the math module in the above program, expression can not access any functions provided by the math
module.
For example, you can make certain methods available (the expression can only use the sqrt() and the pow() methods along with __builtins__
):
from math import *
print(eval('dir()', {'sqrt': sqrt, 'pow': pow}))
output
['__builtins__', 'pow', 'sqrt']
It is also possible to change the name of the method available for the expression
as you want:
from math import *
names = {'square_root': sqrt, 'power': pow}
print(eval('dir()', names))
# Using square_root in Expression
print(eval('square_root(9)', names))
output
['__builtins__', 'power', 'square_root']
3.0
In the above program, square_root()
calculates the square root using sqrt()
.
However, trying to use sqrt()
directly will raise an error.
You can restrict the use of __builtins__
in the expression as follows:
eval(expression, {'__builtins__': None})
3. Passing both globals and locals dictionary
To expose specific functions and variables for use within the eval()
function, you can pass a dictionary to the locals
parameter. This allows you to control which names are considered local within the evaluated expression.
For example, in the following program, expressions evaluated by eval()
function can have sqrt()
method and variable a
only. All other methods and variables are unavailable.
from math import *
a = 144
result = eval('sqrt(a)', {'__builtins__': None}, {'a': a, 'sqrt': sqrt})
print(result) # Output: 12.0
output
12.0