Python - Python Sandboxing and Secure Execution
Python sandboxing refers to the practice of executing code in a controlled and restricted environment so that untrusted or potentially harmful code cannot damage the system, access sensitive data, or perform malicious operations. This concept is especially important in applications such as online code editors, plugin systems, automation platforms, and any system that allows users to submit and run their own Python code.
1. Why Sandboxing is Necessary
Python is a powerful and flexible language that allows access to system-level resources such as files, network connections, memory, and operating system commands. If untrusted code is executed without restrictions, it can:
-
Delete or modify files
-
Access confidential data
-
Execute system commands
-
Consume excessive CPU or memory (Denial of Service)
-
Open network connections for malicious purposes
Because of this, sandboxing is required to limit what the executed code can do.
2. Challenges in Python Sandboxing
Creating a secure sandbox in Python is difficult due to the dynamic and introspective nature of the language. Some challenges include:
-
Python allows runtime modification of objects (reflection and introspection)
-
Built-in functions like
eval(),exec(), and__import__()can bypass restrictions -
Access to internal objects via attributes such as
__class__,__bases__, and__subclasses__ -
Ability to reconstruct restricted functionality indirectly
For these reasons, simple approaches like removing certain built-ins are not fully secure.
3. Basic Sandboxing Techniques
a) Restricting Built-in Functions
You can limit access to dangerous functions by controlling the __builtins__ dictionary.
Example:
safe_globals = {
"__builtins__": {
"print": print,
"len": len,
"range": range
}
}
exec("print(len(range(5)))", safe_globals)
This prevents access to functions like open, eval, or exec. However, this is not fully secure because Python provides ways to bypass these restrictions.
b) Using Restricted Execution Libraries
Some libraries attempt to provide safer execution environments:
-
RestrictedPython (used in Zope)
-
PyPy sandbox (runs Python in a restricted interpreter)
These tools limit available operations but still require careful configuration.
c) Limiting Resources
To prevent abuse, resource limits can be applied:
-
CPU time limits
-
Memory limits
-
File system access restrictions
In Linux, this can be done using resource module:
import resource
resource.setrlimit(resource.RLIMIT_CPU, (1, 1)) # limit CPU time
4. Process-Level Isolation (Recommended Approach)
Instead of relying only on Python-level restrictions, a more secure approach is to isolate execution at the operating system level.
a) Running Code in a Separate Process
Untrusted code can be executed in a separate process with restricted permissions.
-
Use subprocesses
-
Kill the process if it exceeds limits
b) Containers
Technologies like Docker allow you to run code in isolated environments with:
-
Limited file system access
-
Restricted networking
-
Controlled CPU and memory usage
c) Virtual Machines
A stronger isolation method where code runs in a completely separate OS environment.
5. Advanced Sandboxing Techniques
a) AST-Based Code Filtering
Instead of executing raw code, parse it using the ast module and allow only safe constructs.
Example:
-
Disallow imports
-
Block attribute access
-
Restrict function calls
This approach helps prevent execution of dangerous operations before runtime.
b) Whitelisting Instead of Blacklisting
Rather than blocking known dangerous features, only allow explicitly safe operations.
For example:
-
Allow arithmetic operations
-
Allow simple loops
-
Disallow file handling and networking
c) Seccomp and OS-Level Security (Linux)
Advanced systems use kernel-level restrictions such as:
-
Seccomp (restrict system calls)
-
AppArmor or SELinux policies
These prevent even low-level system misuse.
6. Common Pitfalls
-
Removing
__builtins__is not enough -
Blocking
importdoes not stop indirect imports -
Attackers can exploit object inheritance chains
-
Sandboxing within the same process is inherently unsafe
Because of these issues, pure Python sandboxing is generally considered unreliable for high-security needs.
7. Best Practices
-
Never execute untrusted code in the main application process
-
Use containers or virtual machines for strong isolation
-
Apply strict resource limits
-
Validate and analyze code before execution
-
Log and monitor execution behavior
8. Real-World Use Cases
-
Online coding platforms (e.g., code judges)
-
Plugin systems in applications
-
Educational tools that run student code
-
Automation systems with user-defined scripts
Conclusion
Python sandboxing is a complex but essential concept when dealing with untrusted code. While basic restrictions can reduce risk, they are not sufficient for complete security. The most reliable approach combines code-level restrictions with operating system-level isolation, ensuring that even if malicious code runs, it cannot harm the host system.