CodeSafe
An open-source Python library for code encryption, decryption, and safe evaluation using Python's built-in AST module, complete with allowed functions, variables, built-in imports, timeouts, and blocked access to attributes.
CodeSafe is an experimental library, and we're still running some tests on it. If you encounter any issues, or have an edge use case, please let us know.
Security Advisory
Critical Vulnerability Fixed in v0.0.5
Versions 0.0.1 through 0.0.4 contain a known sandbox escape vulnerability in safe_eval() that allows arbitrary code execution.
- Vulnerability: The
safe_eval()function in versions 0.0.1-0.0.4 is vulnerable to a sandbox escape via indirect subscript lookup (e.g.,__builtins__['exec'](...)). This bypasses the AST validation and allows execution of arbitrary Python code. - Impact: An attacker controlling an expression passed to
safe_eval()can execute arbitrary Python code with the application's permissions. - Affected Versions: 0.0.1, 0.0.2, 0.0.3, 0.0.4
- Fixed In: Version 0.0.5 and later
If you are using any version from 0.0.1 to 0.0.4, you should upgrade to version 0.0.5 or later immediately. These earlier versions should not be used in untrusted expression evaluation environments.
The fix includes:
- Rejecting all
ast.Callnodes unless the exact target is explicitly whitelisted (including calls via subscript, attribute, and other indirect targets) - Using a minimal built-ins allowlist that excludes dangerous functions like
exec,eval,compile, and__import__ - Added comprehensive regression tests for indirect call targets
Vulnerability & Security Testing (test_poc.py)
CodeSafe v0.0.5+ includes a rigorous test suite (TestVulnerabilityFixes and TestEdgeCases in test_poc.py) to systematically verify that safe_eval blocks sandbox escapes while preserving standard evaluation features.
Test Results Summary
49/49 Security & Edge Case Tests Passing (100% Pass Rate across all vector categories)
| Attack Vector / Category | Specific Vectors Tested | Status |
|---|---|---|
| AST Subscript & Indirect Calls | __builtins__['exec'](), __builtins__['eval'](), __builtins__['__import__'](), getattr(__builtins__, 'exec'), nested subscript access |
[PASS] Blocked |
| Dunder Attribute Escapes | __class__, __bases__, __mro__, __subclasses__, __globals__, __closure__, __code__ |
[PASS] Blocked |
| Class Hierarchy Traversal | object.__subclasses__(), type().subclasses() |
[PASS] Blocked |
| Expression Bypasses | Comprehensions (list, dict, set), generator expressions, short-circuit logic (and/or), ternary operators, tuple unpacking, walrus operator (:=), lambda calls |
[PASS] Blocked |
| Module & I/O Execution | Direct/from import, os.system, subprocess, io.open, socket, requests, urllib, pathlib write operations |
[PASS] Blocked |
| Dangerous Built-ins | exec(), eval(), compile(), input(), open() (default settings), modifying __builtins__ |
[PASS] Blocked |
| Functional Baseline | Safe arithmetic, string/list/dict operations, standard safe builtins (len, max, abs), explicitly allowed functions |
[PASS] Working |
Running the Proof of Concept Tests
To run the security PoC suite locally:
python -m unittest test_poc.py -v
Changelog v0.0.5:
- Security Fix: Patched critical sandbox escape vulnerability in
safe_eval()(CVE pending) - Blocked indirect function calls via
ast.Subscript,ast.Attribute, and other non-ast.Nametargets - Implemented minimal safe builtins whitelist excluding
exec,eval,compile,__import__, and similar dangerous functions - Added regression tests for indirect call bypass attempts
Changelog v0.0.4:
- Major performance optimizations for encryption and decryption (~10x speedup).
- Optimized
safe_evalby pre-filtering builtins and reducing internal overhead. - Added support for
bytesinput inencrypt. - Added support for file-like stream objects in
runanddecrypt_to_file. - Standardized error handling (replaced
printwith exceptions).
Changelog v0.0.3:
- Added an
allow_attributesparameter tosafe_evaland setimmediate_terminationto beTrueby default for safer function calling.
Changelog v0.0.2:
- Fixed function returns.
- Added error handling to
CodeSafe, removed some print statements with edits from@0XC7R.
Changelog v0.0.1:
- Initial release
Installation
You can install CodeSafe using pip:
pip install codesafe
Supported Python Versions
CodeSafe supports the following Python versions:
- Python 3.6
- Python 3.7
- Python 3.8
- Python 3.9
- Python 3.10
- Python 3.11/Later (Preferred)
Please ensure that you have one of these Python versions installed before using CodeSafe. CodeSafe may not work as expected on lower versions of Python than the supported.
Features
- Safe Eval: Safely allow
eval()expressions to run, while maintaining complete control over the entire evaluation process. - Code Encryption/Decryption: Quickly encrypt your code. This is meant for code obfuscation, and not high-level encryption.
- Run encrypted code at runtime: Run your encrypted code files, without needing to expose your code to end-users.
Usage
Safe Eval
from codesafe import safe_eval
if __name__ == '__main__':
# Run a normal, safe expression
expression = "1 + 1"
disallowed_expression = "os.getcwd()"
result1 = safe_eval(expression, timeout=10, immediate_termination=True)
result2 = safe_eval(disallowed_expression, timeout=10, immediate_termination=True)
Encrypt & Run Code
from codesafe import encrypt_to_file, decrypt_to_file, run
code = """
greetJohnny = "Hello Johnny!"
def greet_someone(greeting):
print(greeting)
greet_someone(greetJohnny)
"""
# Encrypt the code
encrypted_file_path = "encrypted_code.encrypt"
encrypt_to_file(code, encrypted_file_path)
# Run the encrypted code
run(encrypted_file_path) # Hello Johnny!
# Decrypt code to another file
output_file = "decrypted_code.py"
decrypt_to_file(encrypted_file_path, output_file)
Contributing
Contributions are welcome! If you encounter any issues, have suggestions, or want to contribute to CodeSafe, please open an issue or submit a pull request on GitHub.
License
CodeSafe is released under the terms of the MIT License (Modified). Please see the LICENSE file for the full text.
Modified License Clause
The modified license clause grants users the permission to make derivative works based on the CodeSafe software. However, it requires any substantial changes to the software to be clearly distinguished from the original work and distributed under a different name.
Metadata
Release files for codesafe 0.0.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| codesafe-0.0.5.tar.gz | 19.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| codesafe-0.0.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 34.5 kB
Release files / codesafe-0.0.5.tar.gz
| Download URL | codesafe-0.0.5.tar.gz |
|---|---|
| Size | 19.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
28fed57f1fa825e4807bdc6f575c399e77e78ed72a937e3a58767b87bf58b40b
|
|
BLAKE2b-256 checksum How to use checksums |
730a132accb2164e39311da7de5200a39d57af763a581cd70d05c6cb81b0b10c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.25
|
Release files / codesafe-0.0.5-py3-none-any.whl
| Download URL | codesafe-0.0.5-py3-none-any.whl |
|---|---|
| Size | 15.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0e44170e2c3ddb2193b1e529813532e2befdf4d4385032c536d76aba196f23e6
|
|
BLAKE2b-256 checksum How to use checksums |
9486c11b018f7183fc08b57e4193231fe6fa101aa9aee4dd4d837967ad3196ff
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.25
|