internal code execution service

Run untrusted code in a hardened, live sandbox.

code-runner is a Piston-style execution service: it isolates code in a locked-down container, streams stdout as it happens, and lets you write to stdin while the process is still running.

interactive sessionjob_8f3a
0.06sdone
POST /run { language: "python", version: "3.12" }
job_8f3a · queued · slot 4/16 acquired
sandbox up · network=none · ro-rootfs · seccomp
who goes there?
ada
hello, ada
write to stdin, mid-runstdin open
exit 041ms cpu · sandbox reaped · slot freed

Four sandboxes ship today. Each language is a folder the worker discovers at boot.

  • python3.12
  • rust1.83
  • r4.4
  • sqlite3
  • + add your own

Already running live exams in production

  • edalef

Request lifecycle

Every execution takes the same locked path.

Read the architecture
  1. your backendany stack · bearer token

    POST /run

  2. apiHono · validates, enqueues

    enqueue

  3. redisjob queue + stdin bus

    BRPOP · claim slot

  4. workerGo · attaches stdio

    create · attach

trust boundary
  1. sandboxruns untrusted code
    • network=none
    • ro-rootfs
    • cap-drop ALL
    • seccomp

    output-only

  2. soketi → browserlive stream, output-only

Everything above the wall is trusted and authenticated. Beyond it, the sandbox runs with no network and a read-only root. Output leaves through soketi, which is output-only toward the client; nothing trusted ever enters that way.

stdin is the only thing that re-enters mid-run, and only back through the trusted worker, never through soketi.

Hardened by default, not by checklist.

Every sandbox starts from a deny-by-default posture. There is no opt-in security to forget; the runner only relaxes what a language image actually needs. Swap the runtime to gVisor with a single env var when you want a second wall.

The hardening model

applied to every container

  • network = none
  • read-only rootfs
  • cap-drop ALL
  • seccomp: deny by default
  • no-new-privileges
  • mem · cpu · pids cgroups

A real session, not a batch job.

Your backend pushes stdin into the still-running process through one SDK call. Output streams to the browser over soketi the moment a byte is written. The sandbox holds its pipes open for the length of the conversation.

Interactive stdin guide
server.tsts
import { CodeRunnerClient } from '@teovilla/code-runner-sdk-node';

const client = new CodeRunnerClient({ baseUrl, token });

const { jobId, channel } = await client.execute({
  language: 'python',
  files: [{ name: 'main.py', content: source }],
});

await client.start(jobId);              // worker boots the sandbox
// the browser is subscribed to `channel`, already streaming stdout
await client.sendStdin(jobId, 'ada\n'); // written while it runs

Three clocks, and any one of them wins.

A session runs under wall time, idle time, and CPU time at once. The first to expire kills the sandbox unconditionally and frees its slot.

How the clocks work
wall30s

Total lifetime from start. The hard ceiling.

idle10s

Time with no stdout and no stdin written.

cpu15s

Accumulated scheduler time, ignores wall-clock.

SIGKILLfirst to expire → sandbox reaped → slot freed.Defaults shown are per-language, set in each manifest.

Adding a language is adding a folder.

No core changes, no language hardcoded anywhere. Drop a manifest and a pre-built image into languages/; the worker picks it up at boot.

languages/go-1.23/manifest.json
{
  "language": "go",
  "version": "1.23",
  "aliases": ["golang"],
  "image": "executor/go:1.23",
  "entrypoint": "main.go",
  "run": ["go", "run", "main.go"],
  "interactive": true
}
languages/go-1.23/Dockerfile
FROM golang:1.23-alpine
# everything the run command needs,
# nothing it doesn't. read-only at
# runtime; the worker mounts code in.
WORKDIR /sandbox
The add-a-language guide

Case study

Thousands of live coding exams, graded as the code runs.

edalef built its online examination platform on code-runner. At Universidad de San Andrés, students sit thousands of programming exams in it. Each one writes and runs code inside its own hardened sandbox, with stdin sent and output streamed live while the process is still running. Every session is bounded by the three clocks and reaped the moment it ends, so no exam ever leaks a container or holds a slot it no longer needs.

Thousands
exams administered
1 : 1
hardened sandbox per student
0
containers or slots leaked
How the live session works

running on code-runner

edalefonline examination platform

Universidad de San Andrés · Buenos Aires, Argentina

from clone to round-trip

Up and running in four commands.

A plain docker compose up is a true no-op for telemetry; nothing leaves your machine until you point it somewhere.

Full quickstart
bash
cp .env.example .env       # safe local defaultsmake build-images          # build the language sandbox imagesdocker compose up          # redis + soketi + api + workermake e2e                   # interactive "hello, world" round-trip
code-runner

An open-source, self-hostable service for running untrusted code in a hardened sandbox, with live stdin and real-time output.

MIT licensed · built with Go, Hono & Redis

precise · hardened · fast