Use RestrictedPython instead of eval to evaluate python code on API specification#798
Conversation
- pyproject.toml: Restrict Python version range to >=3.10,<3.14 to ensure compatibility with RestrictedPython package requirements.
- compile_restricted() prevents dangerous code compilation - safe_globals/safe_builtins limit available functions - Sandboxed execution environment for `mode='eval'`
- Remove top imports with `# noqa: F401` - Created ALLOWED_MODULES to store configurable modules to import - Add `_get_allowed_modules()` helper method
There was a problem hiding this comment.
Wow, this looks great! I can't believe this is finally happening. Thanks a lot for the implementation, @Pradhvan 🙇♀️ I was feeling a bit rusty with ScanAPI, so it took me a while to jump in, but glad I did!
Thinking about the tests — maybe we could expand test_code_evaluator.py with some extra cases, like:
-
Allowed modules
Confirm only the modules inALLOWED_MODULESare usable.
Examples:datetime.datetime.now(),math.sqrt(16),random.randint(1, 10),re.match("a", "abc"),time.time(),uuid.uuid4() -
Disallowed modules
Ensure importing/using modules not inALLOWED_MODULESraisesInvalidPythonCodeError.
Examples:import os; os.system("ls"),import sys -
Safe built-ins only
Verify that dangerous built-ins are blocked.
Examples:open("file.txt"),exec("print(1)"),eval("2+2") -
Restricted attributes
Block access to dunder and non-whitelisted attributes/methods.
Examples:__import__('os').system('ls'),().__class__.__mro__,(lambda:0).__globals__ -
Side effects
Prevent unintended state mutation or persistence between runs.
Examples:globals()["x"] = 1, setting a var and checking if it persists across executions -
Error messages
Ensure raised errors include both a helpful message and the offending code — and it looks like the offending code part isn’t currently covered by tests. -
Unicode handling
Guarantee correct behavior with Unicode and non-ASCII content.
Examples:u"áéíóú"[::-1], identifiers likeá = 42 -
Isolation
Ensure evaluations are independent between runs.
Examples:len("a")thenlen("bb")without state leaking
Also, we can open an issue at the https://github.com/scanapi/examples for adding some examples that would test some of these cases (I can work on it if you like the idea).
What do you think?
Sounds like a plan @camilamaia 🙌🏾, I can start with updating unit tests from the above mentioned lists. Post that I can take a poke at updating integration tests with the examples repo.
Feel free to open up an issue and I can update it once we are done with this PR. |
- Updated Class InvalidPythonCodeError to have `self.expression = code` - Added unit tests to check updated code_evaluators changes.
|
@camilamaia unit tests updated and logging added. 🚀
|
camilamaia
left a comment
There was a problem hiding this comment.
NICEEEEEEEEEE, let's merge it!! 😍
|
Niceee! I've just added the example issue here: scanapi/examples#32 |
Description
Security: Replace unsafe eval() with RestrictedPython
compile_restricted()+ sandboxed execution contextMotivation behind this PR?
The
CodeEvaluatorclass uses unsafeeval(), which poses security risks when evaluating user-provided Python code in API specifications.What type of change is this?
Could be a Breaking Change since we refactored
CodeEvaluatorclass. Would need to test thoroughly.Checklist
Issue
Closes #51