A sandboxed code execution engine.
Codize Sandbox is the code execution engine that powers Codize in production, running arbitrary code safely inside Linux namespace jails (google/nsjail). It exposes an HTTP API to receive code, execute it in an isolated environment, and return the output.
| Runtime | Identifier |
|---|---|
| Node.js | node |
| TypeScript | node-typescript |
| Ruby | ruby |
| Go | go |
| Python | python |
| Rust | rust |
| Bash | bash |
The container must run in privileged mode (required for nsjail to create Linux namespaces) with --cgroupns=host (required for nsjail to manage cgroups for resource limiting).
$ docker run \
--privileged \
--cgroupns=host \
-p 8080:8080 \
ghcr.io/codize-dev/sandbox:latest serveBehavior can be customized via CLI flags (see CLI Flags for the full list):
$ docker run \
--privileged \
--cgroupns=host \
-p 8080:8080 \
ghcr.io/codize-dev/sandbox:latest serve --run-timeout 10 --compile-timeout 10Create a compose.yml:
services:
sandbox:
image: ghcr.io/codize-dev/sandbox:latest
privileged: true
cgroup: host
command: ["serve", "--run-timeout", "10", "--compile-timeout", "10"]
ports:
- "8080:8080"$ docker compose up| Flag | Default | Description |
|---|---|---|
--port |
8080 (overridden by PORT env var) |
Listen port |
--run-timeout |
30 |
Run timeout in seconds |
--compile-timeout |
30 |
Compile timeout in seconds |
--output-limit |
1048576 (1 MiB) |
Maximum combined output bytes |
--max-files |
10 |
Maximum number of files per request |
--max-file-size |
262144 (256 KiB) |
Maximum file size in bytes |
--max-body-size |
5242880 (5 MiB) |
Maximum request body size in bytes |
--max-concurrency |
10 |
Maximum number of concurrent sandbox executions |
--max-queue-size |
50 |
Maximum number of requests waiting in the execution queue |
--queue-timeout |
30 |
Maximum time in seconds a request waits in the execution queue |
--metrics |
false |
Enable the /metrics endpoint |
Returns the service health status. Intended for load balancer health checks, Docker health checks, and Kubernetes liveness probes.
Response:
{"status":"ok"}Request:
{
"runtime": "node",
"files": [
{
"name": "index.js",
"content": "console.log(\"Hello, World!\")"
}
]
}runtime(required): one of"node","node-typescript","ruby","go","python","rust","bash"files(required): array of source files. The first file in the array is used as the entrypointname(required): file namecontent(required): file content as plain text (default) or Base64-encoded stringbase64_encoded(optional, default:false): whentrue,contentis treated as a Base64-encoded string and decoded by the server
Response:
{
"compile": null,
"run": {
"stdout": "SGVsbG8sIFdvcmxkIQo=",
"stderr": "",
"output": "SGVsbG8sIFdvcmxkIQo=",
"exit_code": 0,
"status": "OK",
"signal": null
}
}compile: compilation result (same schema asrun).nullfor interpreted runtimes (node, ruby, python, bash). When compilation fails,runisnullrun: execution result.nullwhen compilation failsstdout/stderr/output: Base64-encoded output.outputis the interleaved combination of stdout and stderrexit_code: process exit codestatus: one of"OK","SIGNAL","TIMEOUT","OUTPUT_LIMIT_EXCEEDED"signal: signal name if the process was killed by a signal (e.g."SIGKILL"),nullotherwise
Returns Prometheus text exposition format metrics. Only available when the --metrics flag is enabled.
Response (Content-Type: text/plain; version=0.0.4; charset=utf-8):
# HELP sandbox_concurrency_active Number of requests currently executing.
# TYPE sandbox_concurrency_active gauge
sandbox_concurrency_active 0
# HELP sandbox_queue_length Number of requests waiting in queue.
# TYPE sandbox_queue_length gauge
sandbox_queue_length 0
# HELP sandbox_concurrency_max Configured maximum concurrent executions.
# TYPE sandbox_concurrency_max gauge
sandbox_concurrency_max 10
# HELP sandbox_queue_max Configured maximum queue size.
# TYPE sandbox_queue_max gauge
sandbox_queue_max 50
POST /v1/run
β Echo HTTP server (request validation, optional Base64 decoding, write files to tmpdir)
β nsjail (execute code in a namespace-isolated environment)
β Return response
Code is isolated by google/nsjail with multiple layers of defense:
- Linux namespaces: PID, network, mount, UTS, IPC, and cgroup namespaces are all isolated. External network access is completely blocked, and loopback communication is also disabled.
- UID/GID mapping: Sandboxed processes run as nobody (65534). Only a single UID is mapped, making setuid impossible.
- Filesystem restrictions: Only the minimum required paths are mounted (shared libraries, device files, user code directory). Everything except the user code directory is read-only.
/tmpis a 64 MiB tmpfs mounted with noexec. - Resource limits: Execution time is enforced by nsjail's
--time_limitand--rlimit_cpu. Cgroups limit PID count, memory, and CPU usage. Rlimits constrain stack size and other per-process resources. - Seccomp-BPF: Dangerous syscalls (io_uring, bpf, mount, ptrace, unshare, etc.) are blocked at the kernel level. Clone calls with namespace creation flags are also blocked.
- Output limits: The process is killed if the combined stdout and stderr exceeds the configured limit.