Runtime

How to run Deno code in a sandbox

Install Deno with its one-line installer in an isolated Linux microVM, then run the file with deno run and only the permissions it needs.

On Runtime, Deno's permission flags get a second wall behind them: a Firecracker microVM with its own kernel. For untrusted code, Deno's own security guide recommends several layers, among them "a sandboxed environment like a VM or MicroVM (gVisor, Firecracker, etc)". Every Runtime sandbox is that layer, with a network switch the host enforces, and a 2 vCPU, 4 GiB sandbox costs $0.03125 an hour while it waits (pricing).

What Deno's permissions do and do not cover

A program run with Deno has no access to files, the network, environment variables or subprocesses unless you grant it with flags such as --allow-net, --allow-read and --allow-write, each of which can be scoped (--allow-net=example.com, --allow-read=./data). Deno also "sets no limits on the execution of code at the same privilege level", and -A grants everything. Its guide recommends using all of these for untrusted code: limited permissions, a Web Worker with fewer permissions, OS sandboxing such as seccomp, and a VM or microVM (Deno security).

Layer What it stops Where it is enforced
Deno permissions File, network, env and subprocess access the flags did not grant Inside the Deno process
Firecracker microVM Reaching your host through a kernel or runtime bug Hardware virtualization
Runtime network rules Any outbound connection, or all but named hosts On the host, outside the VM
Command timeout and lease Loops that never end; a sandbox left running Runtime's API and host

Root inside the sandbox cannot change the last two (security).

Install Deno and run a file

Deno is not in the default image. Its Linux installer is one command and puts the binary in $HOME/.deno/bin/deno (Deno installation), which in a sandbox is /workspace/.deno/bin/deno. The installer needs unzip, which the image has. v2.9.7 was the latest release on 25 September 2026.

TypeScriptimport { Sandbox } from "withruntime";const program = `const text = await Deno.readTextFile("./input.txt");console.log(text.trim().split(/\\s+/).length, "words");`;await using sbx = await Sandbox.create({  network: { internet: true, allow: ["deno.land", "*.deno.land"] },  timeoutSeconds: 600,  onLeaseEnd: "stop",});await sbx.exec("curl -fsSL https://deno.land/install.sh | sh -s v2.9.7", {  check: true,  timeoutMs: 180_000,});await sbx.network.set({ internet: false });await sbx.files.write("/workspace/input.txt", "one two three four");await sbx.files.write("/workspace/count.ts", program);const deno = "/workspace/.deno/bin/deno";const run = await sbx.exec([deno, "run", "--allow-read=./input.txt", "count.ts"], {  timeoutMs: 30_000,});console.log(run.stdout); // 4 words
Pythonfrom withruntime import Sandboxprogram = """const text = await Deno.readTextFile("./input.txt");console.log(text.trim().split(/\\s+/).length, "words");"""with Sandbox.create(    network={"internet": True, "allow": ["deno.land", "*.deno.land"]},    timeout_seconds=600,    on_lease_end="stop",) as sbx:    sbx.exec("curl -fsSL https://deno.land/install.sh | sh -s v2.9.7", check=True, timeout_ms=180_000)    sbx.network.set(internet=False)    sbx.files.write("/workspace/input.txt", "one two three four")    sbx.files.write("/workspace/count.ts", program)    deno = "/workspace/.deno/bin/deno"    run = sbx.exec([deno, "run", "--allow-read=./input.txt", "count.ts"], timeout_ms=30_000)    print(run.stdout)  # 4 words

The installer script and the Deno download both come from deno.land names, so the allow list is two entries. The version argument pins the release; with none, the script fetches the latest.

Type-check before running

deno run strips types and does not check them. deno check, or deno run --check, runs the TypeScript compiler first (Deno TypeScript):

Terminal/workspace/.deno/bin/deno check count.ts/workspace/.deno/bin/deno run --check --allow-read=./input.txt count.ts

Deno in every sandbox

Install Deno once in a custom image. The installer honours DENO_INSTALL, so pointing it at /usr/local puts deno in /usr/local/bin, on the sandbox user's PATH:

TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({  name: "deno",  recipe: {    commands: ["curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh -s v2.9.7"],  },});await using sbx = await runtime.sandboxes.create({ image: "deno", network: { internet: false } });await sbx.files.write("/workspace/hi.ts", "console.log(`deno ${Deno.version.deno}`);");console.log((await sbx.exec(["deno", "run", "hi.ts"])).stdout);
Pythonfrom withruntime import Runtimeruntime = Runtime()runtime.images.build(name="deno", recipe={    "commands": ["curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh -s v2.9.7"],})with runtime.sandboxes.create(image="deno", network={"internet": False}) as sbx:    sbx.files.write("/workspace/hi.ts", "console.log(`deno ${Deno.version.deno}`);")    print(sbx.exec(["deno", "run", "hi.ts"]).stdout)

Recipe commands run as root in /workspace. Building the image is free, and a stored image is charged on its size.

Deno or Node in a sandbox?

  • Deno when the code should run with no permissions by default, or when a project already uses deno.json and JSR packages.
  • Node.js or Bun when you want no install at all: both are in every sandbox (Node.js, Bun).

Deno can also be installed from npm with npm install -g deno; its docs note this slows Deno's startup and recommend the shell installer.

New accounts get 50 free sandbox hours, no card:

Terminalnpx withruntime sandbox run --trial -- bash -c 'curl -fsSL https://deno.land/install.sh | sh && ~/.deno/bin/deno --version'

Sources

Facts on this page were checked on 25 September 2026.