-6

Imagine an application which asks for user input as a python expression to evaluate (with variable interpolation).

Executing user-supplied code is risky. How should I code this safely in python3? Is there a solution as simple as eval("insert-user-defined-python-expressions-here") that can be trusted?

Zoe
  • 27,060
  • 21
  • 118
  • 148
  • Please refrain from editing your question into a completely different one one; duplicate or not, it invalidates existing answers, which isn't okay. – Zoe Dec 29 '21 at 21:33
  • 2
    The mod comment telling you not to edit your question that invalidates existing answers is _right there_. If you have a different question, ask that anew. But looking at your new question: `results_str` should actually be a `dict` as per [the documentation](https://ipwhois.readthedocs.io/en/latest/ipwhois.html?highlight=lookup_rdap#ipwhois.ipwhois.IPWhois.lookup_rdap). This would mean you are trying to solve a problem that isn't there. And your printed output disagrees with your code: your code has single quotes around the string and your printed output has triple double quotes. MCVE please. – Andras Deak -- Слава Україні Dec 30 '21 at 23:31
  • @Zoe, I'm allowed to edit my question for clarification. It's still a dupe. Please do not revert my edits. –  Dec 30 '21 at 23:31
  • @AndrasDeak, I'm allowed to edit my question for clarification. Too hard to comprehend? We can take it to meta –  Dec 30 '21 at 23:33
  • 2
    @MikePennington It still invalidates existing answers; See https://meta.stackoverflow.com/a/332863/6296561 for one of many meta posts that all state "**Please do _not_ change your question after you have gotten an answer.** Improvements such as grammar and formatting corrections are fine but your edits should not invalidate existing answers. If you need to ask a new question, create a new post." – Zoe Dec 30 '21 at 23:33
  • 2
    @MikePennington Please take it to meta, I'd enjoy that – Nick is tired Dec 30 '21 at 23:33
  • it's not a completely different question @zoe... –  Dec 30 '21 at 23:35
  • 2
    Zoe is not a subject matter expert (which is to say she's taken action on your question as a moderator). I am. Your new question has nothing to do with "how do I make `eval` safe?" which was your old question. Trying to parse a dict-like string (that might not actually be a string) is a different question. One that is probably a dupe, but we'll only know for sure when you've asked it with a [mcve]. – Andras Deak -- Слава Україні Dec 30 '21 at 23:36

1 Answers1

4

Short answer: no, there is no solution as simple as somehow calling eval that's magically safe.

You said in a comment that this question is not a duplicate of Python: make eval safe, although the title sounds the same, and the top answers say the same thing:

  1. No, you can't make eval safe.
  2. Use ast.literal_eval if that works for you, otherwise you need a dedicated parser that only parses what you prepare for.

One would think that if there's a way to make eval safe then people would have done so already. And they have! We have pysandbox. Or, uh, we don't have it. It's archived and it has this banner:

WARNING: pysandbox is BROKEN BY DESIGN, please move to a new sandboxing solution (run python in a sandbox, not the opposite!)

See also https://lwn.net/Articles/574215/.


To be a bit more specific, let me attack the approach in your self-answer:

def not_actually_safe_eval(s):
    # your suggestion of a "safe eval" that is NOT SAFE
    vals = {"jj": None, "kk": None}
    return eval(compile(s, filename="<string>", mode="exec"), {}, vals)

# courtesy of Ned Batchelder https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
# updated to Python 3.9
s = """
(lambda fc=(
    lambda n: [
        c for c in
            ().__class__.__bases__[0].__subclasses__()
            if c.__name__ == n
        ][0]
    ):
    fc("function")(
        fc("code")(
            0,0,0,0,0,0,b"KABOOM",(),(),(),"","",0,b""
        ),{}
    )()
)()
"""

not_actually_safe_eval(s)

This is what this script does:

$ python not_actually_safe_eval_demo.py 
Segmentation fault

We can agree that if your approach can cause the interpreter to segfault given certain inputs, it's not safe.

You can start trying to get around this approach, fix more and more edge cases. The bottom line is the same.

Eval cannot reasonably be made safe. Don't call it (or exec) on untrusted inputs. If you want to sandbox python, put python itself in an isolated environment from which bad actors cannot get out of.