Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Can you protect a python variable with exec()?

This is kind of a hacky Python question.

Consider the following Python code:

def controlled_exec(code):
  x = 0
  def increment_x():
    nonlocal x
    x += 1

  globals = {"__builtins__": {}} # remove every global (including all python builtins)
  locals = {"increment_x": increment_x} # expose only the increment function

  exec(code, globals, locals)

  return x

I expect this function to provide a controlled code API, which simply counts the number of increment_x() calls. I tried it and I get the correct behavior.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

# returns 2
controlled_exec("""\
increment_x()
increment_x()
""")

I assume this way of doing is not secure, but I wonder out of curiosity. Can I set x to an arbitrary value (say negative) by executing code via controlled_exec(...) ? How would I do that?

>Solution :

Yes, x can be set to an arbitrary value by code executed by controlled_exec.

Consider the following demo:

def controlled_exec(code):
  x = 0
  def increment_x():
    nonlocal x
    x += 1
    print(f"{x=}")

  globals = {"__builtins__": {}} # remove every global (including all python builtins)
  locals = {"increment_x": increment_x} # expose only the increment function

  exec(code, globals, locals)

  return x


controlled_exec("""\
increment_x()
increment_x.__closure__[0].cell_contents = -100
increment_x()
""")

This outputs

x=1
x=-99

This is really no way to "secure" exec. No matter what you do, at the end of the day you’re executing arbitrary Python code, which is just as free to access and modify the state of the Python interpreter as the code that you write.

To highlight just how difficult it would be meaningfully secure exec, note that despite your attempt to hide builtins from the executed code, an attacker can still access any builtin via

increment_x.__globals__['__builtins__']

This is just one of dozens of tricks that someone trying to exploit this function could use.

The fact that we can modify the variable x is really a tame example. There’s literally nothing stopping the code passed to controlled_exec from doing more disastrous things, like wiping your hard drive or downloading malware.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading