diff --git a/Tests/test_imagemath.py b/Tests/test_imagemath.py index 2329b74..d3b7ba3 100644 --- a/Tests/test_imagemath.py +++ b/Tests/test_imagemath.py @@ -58,6 +58,12 @@ class TestImageMath(PillowTestCase): self.assertEqual(pixel( ImageMath.eval("float(B)**33", images)), "F 8589934592.0") + def test_prevent_exec(self): + self.assertRaises(ValueError, ImageMath.eval("exec('pass')")) + self.assertRaises(ValueError, ImageMath.eval("(lambda: exec('pass'))()")) + self.assertRaises(ValueError, ImageMath.eval("(lambda: (lambda: exec('pass'))())()")) + + def test_logical(self): self.assertEqual(pixel(ImageMath.eval("not A", images)), 0) self.assertEqual(pixel(ImageMath.eval("A and B", images)), "L 2") diff --git a/src/PIL/ImageMath.py b/src/PIL/ImageMath.py index c5bea70..13839e4 100644 --- a/src/PIL/ImageMath.py +++ b/src/PIL/ImageMath.py @@ -263,7 +263,18 @@ def eval(expression, _dict={}, **kw): if hasattr(v, "im"): args[k] = _Operand(v) - out = builtins.eval(expression, args) + compiled_code = compile(expression, "", "eval") + def scan(code): + for const in code.co_consts: + if type(const) == type(compiled_code): + scan(const) + + for name in code.co_names: + if name not in args and name != "abs": + raise ValueError(f"'{name}' not allowed") + + scan(compiled_code) + out = builtins.eval(expression, {"__builtins": {"abs": abs}}, args) try: return out.im except AttributeError: