Why this page exists

Elo gives you a capability sandbox by construction — compiled code can't do I/O, can't call eval, can't touch host globals (see Security). It does not give you a resource sandbox: a legal expression can still spend a lot of time or memory over the data you give it. If the people writing the expressions aren't fully trusted (the common case), you must add that resource sandbox yourself.

The patterns below are minimal, correct starting points — not hardened products. Copy the one for your target from contrib/sandboxes/ in the repository and tune the limits to your workload.

The baseline — four levers, every target

  • Isolate. Run the emitted code in its own thread, process, or context — never inline on the thread that must stay responsive.
  • Cap memory. Give it a hard memory ceiling so a large allocation fails instead of taking the host down.
  • Cap time. Give it a wall-clock (or CPU) timeout and hard-kill on expiry — this is what stops a runaway synchronous computation.
  • Pass data only. The input must be plain data (JSON-shaped), never a live host object whose methods could run.

A capability bug in Elo would be our fault and we'd fix it; isolating the run anyway gives you defense-in-depth for free.

Node.js (server)

Compile in your trusted process; run only the output in a worker_threads worker. The worker gives you both missing levers at once: it caps the V8 heap via resourceLimits.maxOldGenerationSizeMb, it runs off your main event loop, and you hard-kill it with worker.terminate() on a timeout.

A common in-house shortcut is to evaluate with the vm module and its timeout option. That interrupts synchronous CPU-bound work (useful!), but it does not cap memory, it runs on the main event loop (one bad expression stalls the whole process), and vm is explicitly not an isolation boundary. Prefer a worker for untrusted expressions.

Reference: contrib/sandboxes/node/.

Browser

Run the emitted code in a Web Worker and hard-kill it with worker.terminate() on a timeout. Pass the input by postMessage, which structured-clones it — enforcing the data-only contract for free. Browsers can't cap a worker's memory directly, so keep inputs small and prefer server-side evaluation for untrusted expressions.

Reference: contrib/sandboxes/browser/.

Ruby

Ruby has no in-process sandbox, so isolate with a child process. Set a memory ceiling with Process.setrlimit(:AS, …) and a CPU ceiling with Process.setrlimit(:CPU, …) in the child, and enforce a wall-clock reaper that sends KILL on expiry. Run the child as a low-privilege user.

Reference: contrib/sandboxes/ruby/.

Python

Same shape: a child process with resource.setrlimit(RLIMIT_AS, …) for memory and RLIMIT_CPU for CPU, launched with a subprocess timeout for the wall-clock kill. Feed the input as JSON on stdin, which keeps it plain data by construction, and keep the child's namespace to the Elo prelude only.

Reference: contrib/sandboxes/python/.

PostgreSQL

The emitted SQL is a pure expression over supplied values and columns. Run it as a dedicated low-privilege, read-only role (no writes, no superuser, restricted search_path), inside a transaction with SET LOCAL statement_timeout for time and a capped work_mem for memory, and pass inputs as bound parameters ($1, …) — never spliced into the SQL text.

One deployment step comes first: unlike the other three targets, SQL's prelude cannot be prepended to the expression, so install it in the database once — eloc --prelude-only -t sql | psql "$DATABASE_URL". It is CREATE OR REPLACE throughout, so re-running it on each deploy is safe. The role that runs expressions needs only EXECUTE on those functions, not the right to create them.

Reference: contrib/sandboxes/postgres/.

What the sandbox is, and isn't, for

The resource sandbox bounds cost — time and memory. It is not where Elo's capability guarantees live: those are by construction in the emitted code. If you ever find emitted code reaching a host capability, or the compiler misbehaving on hostile input, that's a bug — please report it through the bug bounty program.