Skip to content

Commit 6674505

Browse files
[doc] exec-used, add a full example writing in an intermediary file (#9913)
1 parent 3be9e42 commit 6674505

File tree

3 files changed

+52
-5
lines changed

3 files changed

+52
-5
lines changed

doc/data/messages/e/exec-used/details.rst

+47-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,53 @@ The available methods and variables used in ``exec()`` may introduce a security
22
You can restrict the use of these variables and methods by passing optional globals
33
and locals parameters (dictionaries) to the ``exec()`` method.
44

5-
However, use of ``exec`` is still insecure. For example, consider the following call
6-
that writes a file to the user's system:
5+
However, use of ``exec()`` is still insecure if you allow some functions like
6+
``__import__`` or ``open``. For example, consider the following call that writes a
7+
file to the user's system and then execute code unrestrained by the ``allowed_globals``,
8+
or ``allowed_locals`` parameters:
79

810
.. code-block:: python
911
10-
exec("""\nwith open("file.txt", "w", encoding="utf-8") as file:\n file.write("# code as nefarious as imaginable")\n""")
12+
import textwrap
13+
14+
15+
def forbid_print(*args):
16+
raise ValueError("This is raised when a print is used")
17+
18+
19+
allowed_globals = {
20+
"__builtins__": {
21+
"__import__": __builtins__.__import__,
22+
"open": __builtins__.open,
23+
"print": forbid_print,
24+
}
25+
}
26+
27+
exec(
28+
textwrap.dedent(
29+
"""
30+
import textwrap
31+
32+
with open("nefarious.py", "w") as f:
33+
f.write(textwrap.dedent('''
34+
def connive():
35+
print("Here's some code as nefarious as imaginable")
36+
'''))
37+
38+
import nefarious
39+
40+
nefarious.connive() # This will NOT raise a ValueError
41+
"""
42+
),
43+
allowed_globals,
44+
)
45+
46+
47+
The import is used only for readability of the example in this case but it could
48+
import a dangerous functions:
49+
50+
- ``subprocess.run('echo "print(\"Hello, World!\")" > nefarious.py'``
51+
- ``pathlib.Path("nefarious.py").write_file("print(\"Hello, World!\")")``
52+
- ``os.system('echo "print(\"Hello, World!\")" > nefarious.py')``
53+
- ``logging.basicConfig(filename='nefarious.py'); logging.error('print("Hello, World!")')``
54+
- etc.

doc/data/messages/e/exec-used/good.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ def get_user_code(name):
33

44

55
username = "Ada"
6-
allowed_globals = {"__builtins__": None}
7-
allowed_locals = {"print": print}
6+
# If the globals dictionary does not contain a value for the key __builtins__,
7+
# all builtins are allowed. You need to be explicit about it being disallowed.
8+
allowed_globals = {"__builtins__": {}}
9+
allowed_locals = {}
810
# pylint: disable-next=exec-used
911
exec(get_user_code(username), allowed_globals, allowed_locals)
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
- `Be careful with exec and eval in Python <https://lucumr.pocoo.org/2011/2/1/exec-in-python/>`_
2+
- `Python documentation <https://docs.python.org/3/library/functions.html#exec>`_

0 commit comments

Comments
 (0)