A lightweight library to run untrusted Python code
Pybox is a lightweight Python library for running untrusted Python code. It tries to offer a reasonable tradeoff between security and user-friendliness.
The untrusted code is executed in a protected Docker sandbox with (most) side-effects disabled. All I/O is passed as JSON via the standard input, standard output and standard error.
Main features:
- ✅ Protected Docker sandbox, offering protection against:
- code escape attempts
- fork bombs (pids_limit)
- memory abuse
- file system writes
- network exfiltration (optional)
- ✅ Optional gVisor integration for enhanced security (highly recommended)
- ✅ Optional fast mode with container pool (faster but less secure)
- ✅ Provides both a Python and a FastAPI interface
Pybox is designed so you can switch between a safe and fast mode:
| Mode | Behavior | Security | Performance |
|---|---|---|---|
| safe (default) | destroy container after each run | ⭐⭐⭐⭐⭐ | slower |
| fast | reuse warm containers | ⭐⭐⭐ | much faster |
Install Pybox with:
pip install -e .
docker build -t pybox:latest pybox/docker/Optionally, follow these instructions to install [gVisor] for enhanced security against kernel exploits.
from pybox import Executor, Config, Payload
cfg = Config(timeout=3.0)
executor = Executor(cfg)
code = "result = x + y"
input = {"x": 2, "y": 3}
payload = executor.run(code, input)
print(payload)
# Payload(status='ok', result=5, errmsg=None, returncode=0, duration=0.5, resources=None)
assert payload.status == 'ok'
assert payload.result == 5.0
assert payload.returncode == 0Pybox includes also a convenient execute() function:
from pybox import ExecuteError, execute
code = """
import math
result = math.hypot(x, y)
"""
input = {"x": 3, "y": 4}
result = execute(code, input, config={"timeout": 3.0})
assert result == 5.0To save raw output to files, set stdout_file and stderr_file in Config:
from pybox import Executor, Config
cfg = Config(
timeout=3.0,
stdout_file=".pybox/stdout.txt",
stderr_file=".pybox/stderr.txt",
)
executor = Executor(cfg)
payload = executor.run("result = x + y", {"x": 2, "y": 3})
assert payload.result == 5.0The files are written on each run, so they work well in a gitignored folder.
Start the service:
uvicorn pybox.api:app --reloadSend a request:
curl -X POST http://localhost:8000/run \
-H "Content-Type: application/json" \
-d '{"code": "result = x + y", "input": {"x": 2, "y": 3}}'It should return a JSON response with the full execution payload:
{
"status": "ok",
"result": 5,
"errmsg": null,
"returncode": 0,
"duration": 0.123,
"resources": null
}Pybox uses MkDocs for its documentation.
To install the documentation dependencies:
pip install -e ".[docs]"Previewing Locally: Run the following command to spin up a local live-reloading server:
mkdocs serveThen, open your browser to http://127.0.0.1:8000.
Building Static HTML: To generate the static HTML files for hosting (e.g., on GitHub Pages):
mkdocs buildTo run the standard test suite and test the documentation code blocks, ensure you have the dev dependencies installed:
pip install -e ".[dev]"Run standard tests:
pytestRun the documentation tests against the README.md to ensure the code examples are valid:
pytest --codeblocks README.md