How to mount an S3 bucket in a sandbox
Store the bucket's key as a Runtime secret, then call sbx.mounts.add({ provider: "s3", bucket, path, secret }).
On Runtime the bucket's key stays outside the sandbox. You store the key once as a secret. The mount client inside the sandbox signs its requests with a placeholder, and Runtime's egress proxy signs each one again with the real key as it leaves for the bucket's endpoint, so code in the sandbox, or a prompt injection steering it, has nothing worth stealing. Amazon S3, Cloudflare R2, Google Cloud Storage and any S3-compatible store work, and a public bucket needs no key at all (mount your own bucket).
Store the key and mount the bucket
Terminalprintf %s "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" | runtime secrets set DATA_BUCKET \ --host s3.eu-west-1.amazonaws.com --header Authorization --format 'AWS4-HMAC-SHA256 {value}'runtime sandbox mount "${id}" s3://my-data/datasets /data --secret DATA_BUCKET --region eu-west-1runtime sandbox mounts "${id}"runtime sandbox unmount "${id}" /dataTypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.secrets.set("DATA_BUCKET", { value: `${process.env.AWS_ACCESS_KEY_ID}:${process.env.AWS_SECRET_ACCESS_KEY}`, hosts: ["s3.eu-west-1.amazonaws.com"], header: "Authorization", format: "AWS4-HMAC-SHA256 {value}",});await using sbx = await runtime.sandboxes.create();await sbx.mounts.add({ provider: "s3", bucket: "my-data", prefix: "datasets", region: "eu-west-1", path: "/data", secret: "DATA_BUCKET",});console.log((await sbx.exec("ls -la /data")).stdout);await sbx.exec("echo 'a,b' > /data/result.csv", { check: true }); // reaches the bucket on closePythonimport osfrom withruntime import Runtimeruntime = Runtime()runtime.secrets.set( "DATA_BUCKET", value=f"{os.environ['AWS_ACCESS_KEY_ID']}:{os.environ['AWS_SECRET_ACCESS_KEY']}", hosts=["s3.eu-west-1.amazonaws.com"], header="Authorization", format="AWS4-HMAC-SHA256 {value}",)with runtime.sandboxes.create() as sbx: sbx.mounts.add(provider="s3", bucket="my-data", prefix="datasets", region="eu-west-1", path="/data", secret="DATA_BUCKET") print(sbx.exec("ls -la /data").stdout)The secret must match exactly: the value ACCESS_KEY_ID:SECRET_ACCESS_KEY
(add :SESSION_TOKEN for temporary keys), the header Authorization, the
format AWS4-HMAC-SHA256 {value}, and the bucket's endpoint as its host.
R2, Google Cloud Storage and other stores
| Provider | Mount with | The secret's host |
|---|---|---|
| Amazon S3 | provider: "s3", region (us-east-1 when omitted) |
s3.<region>.amazonaws.com |
| Cloudflare R2 | provider: "r2", accountId |
<account id>.r2.cloudflarestorage.com |
| Google Cloud Storage | provider: "gcs", with an HMAC key |
storage.googleapis.com |
| Any S3-compatible | provider: "s3", endpoint |
Your store's own host |
| A public bucket | Any of the above, no secret |
None |
TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create();await sbx.mounts.add({ provider: "r2", accountId: "<cloudflare account id>", bucket: "models", path: "/models", secret: "R2_MODELS", readOnly: true,});console.log(await sbx.mounts.list());prefix mounts only the keys under it, and readOnly refuses writes, which
suits a shared dataset that jobs must not change.
How the mount behaves
| Question | Answer |
|---|---|
| What runs it | rclone, installed in the sandbox the first time you mount, a few seconds more |
| When a write reaches the bucket | When the file is closed |
| Two sandboxes, one bucket | Both can mount it; a file both write ends as the last one closed |
| Pause and wake | The mount lasts through both |
| Stop and restart | The mount ends at a stop; mount it again after a restart |
| Network | HTTPS to the endpoint, through the sandbox's own rules, like any other host |
| Where the key lives | Sealed on Runtime's servers; no API, tool or command returns it |
A mount, a volume or the AWS SDK?
- A mount fits data that already lives in a bucket: datasets, model files, results other systems read.
- A volume is a disk that outlives sandboxes, on the sandbox's own server, for data a program writes and rereads many times, such as a package cache or a database file.
- The AWS SDK with an identity token fits code that calls S3's API itself, for listing, presigned URLs or other AWS services, with no key at all (use identity tokens with AWS).
Mistakes and how Runtime handles them
- The secret's host does not match the endpoint. The proxy adds the real
key only on HTTPS requests to the secret's hosts. For S3 that is the
regional host,
s3.<region>.amazonaws.com. - Pasting the key into an environment variable. Then it lives in the sandbox. With the secret, a sandbox that prints its whole environment shows a worthless placeholder.
- Writing a file and reading it from elsewhere at once. It reaches the bucket when it is closed; close it, or finish the program, first.
- An allow list that leaves the bucket out. The bucket is reached through the sandbox's network rules. Allow its endpoint host when you narrow them (turn off sandbox internet).
- An MCP agent. The same mounts are the
runtime_sandbox_mount,runtime_sandbox_mountsandruntime_sandbox_unmounttools.
Start
Terminalnpx withruntime sandbox run --trial --keep -- ls /workspaceNew accounts get 50 free sandbox hours, no card. Then mount a bucket into the
sandbox it kept with runtime sandbox mount.
Facts on this page were checked on 25 September 2026.