# How to compile and run Rust code in a sandbox Install Rust with rustup or Ubuntu's `rustc` and `cargo` in an isolated microVM, build the code there, and run it with the network off. **On Runtime, untrusted Rust is contained twice over: at build time and at run time.** Cargo compiles a package's `build.rs` and runs it just before building the package, so the build runs other people's code and belongs in the sandbox as much as the binary does. Every Runtime sandbox is a Firecracker microVM with its own kernel, `gcc` and `sudo`, and a 2 vCPU, 4 GiB sandbox costs $0.08 an hour with both CPUs compiling ([pricing](/docs/pricing)). ## Which Rust to install | Source | Package or command | Version on 25 September 2026 | | ------------------------------- | ------------------------------------- | ---------------------------------- | | Ubuntu 24.04 archive (main) | `sudo apt-get install -y rustc cargo` | 1.75.0 | | Ubuntu 24.04 archive (universe) | `sudo apt-get install -y rustc-1.80` | 1.80.1 | | rustup, the official installer | the `sh.rustup.rs` script, below | 1.98.1, the current stable release | The image has none of these; it has the C toolchain (`gcc`, `g++`, `make`) that crates with C code build against. Pick rustup when your code or its crates need a recent compiler. ## Install with rustup and run a program rustup installs `rustc`, `cargo` and `rustup` into `~/.cargo/bin` ([Rust](https://rust-lang.org/tools/install/)); in a sandbox, home is `/workspace`. `-y` skips the prompts and `--profile minimal` leaves out the docs ([rustup](https://rust-lang.github.io/rustup/installation/other.html)). ```ts check import { Sandbox } from "withruntime"; const program = `fn main() { let words = ["sandbox", "microvm", "kernel"]; let longest = words.iter().max_by_key(|w| w.len()).unwrap(); println!("{longest}"); } `; await using sbx = await Sandbox.create({ diskMiB: 8192, timeoutSeconds: 1200, onLeaseEnd: "stop" }); await sbx.exec( "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal", { check: true, timeoutMs: 600_000 }, ); await sbx.network.set({ internet: false }); // compile and run offline await sbx.files.write("/workspace/job/main.rs", program); const cargoBin = "/workspace/.cargo/bin"; const build = await sbx.exec([`${cargoBin}/rustc`, "-O", "main.rs", "-o", "main"], { cwd: "/workspace/job", timeoutMs: 300_000, }); if (build.exitCode !== 0) console.error(build.stderr); const run = await sbx.exec(["./main"], { cwd: "/workspace/job", timeoutMs: 10_000 }); console.log(run.stdout); // sandbox ``` ```python check from withruntime import Sandbox program = """fn main() { let words = ["sandbox", "microvm", "kernel"]; let longest = words.iter().max_by_key(|w| w.len()).unwrap(); println!("{longest}"); } """ with Sandbox.create(disk_mib=8192, timeout_seconds=1200, on_lease_end="stop") as sbx: sbx.exec("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal", check=True, timeout_ms=600_000) sbx.network.set(internet=False) # compile and run offline sbx.files.write("/workspace/job/main.rs", program) cargo_bin = "/workspace/.cargo/bin" build = sbx.exec([f"{cargo_bin}/rustc", "-O", "main.rs", "-o", "main"], cwd="/workspace/job", timeout_ms=300_000) if build.exit_code != 0: print(build.stderr) run = sbx.exec(["./main"], cwd="/workspace/job", timeout_ms=10_000) print(run.stdout) # sandbox ``` - **Disk:** the default 4 GiB sandbox had about 2.5 GiB free on 24 September 2026. A toolchain and a `target` folder add up, so ask for 8 GiB. - **Time:** give the install and each build a `timeoutMs`; the default is 60 seconds. The sandbox's lease (`timeoutSeconds`) can run up to an hour ahead and be extended. - **Errors:** compiler errors are on `stderr`. Return them to the model that wrote the code as they are. ## A Cargo project Fetch the crates with the internet on, then build and test offline, so neither `build.rs` nor the tests can call out: ```ts check import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create({ image: "rust", diskMiB: 8192, timeoutSeconds: 3600, onLeaseEnd: "stop", }); await sbx.files.upload("./my-crate", "/workspace/crate"); await sbx.exec("cargo fetch", { cwd: "/workspace/crate", check: true, timeoutMs: 600_000 }); await sbx.network.set({ internet: false }); const test = await sbx.exec(["cargo", "test", "--offline"], { cwd: "/workspace/crate", timeoutMs: 1_800_000, onStdout: (text) => process.stdout.write(text), onStderr: (text) => process.stderr.write(text), }); console.log("exit", test.exitCode); ``` ```python check import sys from withruntime import Sandbox with Sandbox.create(image="rust", disk_mib=8192, timeout_seconds=3600, on_lease_end="stop") as sbx: sbx.files.upload("./my-crate", "/workspace/crate") sbx.exec("cargo fetch", cwd="/workspace/crate", check=True, timeout_ms=600_000) sbx.network.set(internet=False) test = sbx.exec(["cargo", "test", "--offline"], cwd="/workspace/crate", timeout_ms=1_800_000, on_stdout=sys.stdout.write, on_stderr=sys.stderr.write) print("exit", test.exit_code) ``` This uses the `rust` image below. Both streams print as the build goes. ## Rust in every sandbox Install the toolchain once in a [custom image](/docs/images) so no sandbox waits for it. rustup reads `RUSTUP_HOME` and `CARGO_HOME` for where to put things and needs them set whenever the toolchain runs ([rustup](https://rust-lang.github.io/rustup/installation/index.html)); a recipe's `env` stays set in every sandbox made from the image. Recipe commands run as root, so the last command lets the sandbox user write Cargo's cache. ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); await runtime.images.build({ name: "rust", recipe: { env: { RUSTUP_HOME: "/usr/local/rustup", CARGO_HOME: "/usr/local/cargo" }, commands: [ "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --no-modify-path", "ln -sf /usr/local/cargo/bin/* /usr/local/bin/", "chmod -R a+w /usr/local/rustup /usr/local/cargo", ], }, }); ``` ```python check from withruntime import Runtime runtime = Runtime() runtime.images.build(name="rust", recipe={ "env": {"RUSTUP_HOME": "/usr/local/rustup", "CARGO_HOME": "/usr/local/cargo"}, "commands": [ "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --no-modify-path", "ln -sf /usr/local/cargo/bin/* /usr/local/bin/", "chmod -R a+w /usr/local/rustup /usr/local/cargo", ], }) ``` For Ubuntu's compiler instead, the recipe is `{ apt: ["rustc", "cargo"] }`. Building an image is free; a stored image is charged on its size. ## Many builds at once Each sandbox is its own machine with its own disk, so parallel builds never share a `target` folder or a lock on Cargo's cache. A paid account runs 100 sandboxes at once to start with. New accounts get 50 free sandbox hours, no card: ```bash no-run npx withruntime sandbox run --trial -- bash -c 'sudo apt-get update -q && sudo apt-get install -y -q rustc && rustc --version' ``` ## Related - [Run Go code in a sandbox](/languages/go) - [How to run untrusted code from an LLM safely](/use-cases/run-untrusted-llm-code) - [A coding agent's sandbox](/use-cases/coding-agent-sandbox) - [Agent evals and SWE-bench](/use-cases/agent-evals-and-swe-bench) ## Sources - Rust installation: https://rust-lang.org/tools/install/ (read 25 September 2026) - Cargo build scripts: https://doc.rust-lang.org/cargo/reference/build-scripts.html (read 25 September 2026) - rustup installation and options: https://rust-lang.github.io/rustup/installation/index.html and https://rust-lang.github.io/rustup/installation/other.html (read 25 September 2026) - Current stable Rust, rustc 1.98.1: https://static.rust-lang.org/dist/channel-rust-stable.toml (read 25 September 2026) - Ubuntu 24.04 package indexes (`rustc` and `cargo` 1.75.0+dfsg0ubuntu1-0ubuntu7.4, `rustc-1.80` 1.80.1+dfsg0ubuntu1-0ubuntu0.24.04.01): http://archive.ubuntu.com/ubuntu/dists/noble-updates/ (read 25 September 2026) Facts on this page were checked on 25 September 2026.