Search code examples
pythonpython-ast

Override functions in exec function


I'm working on a mobile app that can execute Python code easily, and unlike other execution apps I am going to have it run with actual Python.

I'm using a Flask Webserver and requests to accomplish this.

This is my code:

@app.route('/exec')
def run():
  exec(request.args.get("code"))

I want to override any print statements or output. Using the string.replace method and another function wont work because if someone uses code like print("Use the print() function to send output in Python!") this would be problematic, and people may want to use the function name. I also want to output errors.

For anyone saying this is unsafe, I have properly sandboxed the server, it will reset around every hour and has a backup server.


Solution

  • There are a few ways to go about this: if you're doing exec from the same process as Flask, the simplest thing to do is call it with a dictionary of "globals" and pass your own print function. You can also replace sys.out to reroute it to your own sink.

    Alternatively, you can write a separate script which reads the input code from stdin, then execs it, and call that script as a subprocess to read from its output directly. That way also allows you to impose stricter limits on the user's code than the Flask code.

    Whichever way you choose, be sure to also handle the case when the user's code raises an exception or falls into an infinite loop (or just takes way too long to run). The handling of those cases will depend on which approach you take.