[Python-ideas] Any chance on (slowly) deprecating `eval` and `exec` as builtins?

Steven D'Aprano steve at pearwood.info
Tue Nov 7 09:41:16 EST 2017


On Tue, Nov 07, 2017 at 03:35:58PM +0200, Serhiy Storchaka wrote:
> 07.11.17 12:29, אלעזר пише:
> >Also, it is unfortunate that `ast.literal_eval` is less accessible than 
> >`builtins.eval`. Giving it an alias in builtins might make it easier for 
> >programmers (and less scary - "ast" might sound like I need a PhD to use 
> >it).
> 
> ast.literal_eval is not so safe as you think. Malicious input can cause 
> a stack overflow in your program. [1]
> 
> [1] https://bugs.python.org/issue31113


I don't see anything about literal_eval in that bug report.

In any case, I think that securing literal_eval is much simpler than 
securing eval:


try:
    # a thousand character expression ought to be enough for 
    # any legitimate purpose...
    value = literal_eval(tainted_string[:1000])  # untested
except MemoryError:
    value = None


versus, well, there's no obvious or simple way to secure eval. You might 
get something reasonable with:

if '_' in tainted_string:
    raise ValueError("no underscores allowed!")
globalns = {'__builtins__': None}  # I think?
eval(tainted_string[:1000], globalns, globalns)

but even that is probably vulnerable to a clever enough attacker.

I tried this on my computer with Python 3.5:


# Build a deeply nested dict {'x':{'x':{...}}} as a string
s = "{'x':0}"
for i in range(1665):
    s = "{'x':%s}" % s

assert len(s) < 10000
d = ast.literal_eval(s)

and it failed with MemoryError rather than a segfault, so that's 
something.



-- 
Steve


More information about the Python-ideas mailing list