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. Runtime's egress proxy signs each request again with the real key, as it leaves for the bucket's endpoint. So code in the sandbox, or a prompt injection that steers it, has nothing worth stealing. Amazon S3, Cloudflare R2, Google Cloud Storage and any S3-compatible store work. 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 sandboxes mount "${id}" s3://my-data/datasets /data --secret DATA_BUCKET --region eu-west-1runtime sandboxes mounts "${id}"runtime sandboxes 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. Its value is ACCESS_KEY_ID:SECRET_ACCESS_KEY,
with :SESSION_TOKEN added for temporary keys. Its header is Authorization.
Its format is AWS4-HMAC-SHA256 {value}. Its host is the bucket's endpoint.
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. readOnly refuses writes. That 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. It adds a few seconds |
| When a write reaches the bucket | When the file is closed |
| Two sandboxes, one bucket | Both can mount it. A file that both write ends with the version closed last |
| 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. It sits on the sandbox's own server. Use it 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. It needs 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 the key lives in the sandbox. With the secret, a sandbox that prints its whole environment shows only a worthless placeholder.
- Reading a file from elsewhere right after writing it. A write reaches the bucket when the file is closed. Close the file, 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_sandboxes_mountstool'smount,listandunmountactions.
Start
Terminalnpx withruntime sandboxes run --keep -- ls /workspaceA new account gets 100 free hours of a 1 GB machine in its first 30 days, with no card needed. Then
mount a bucket into the sandbox it kept, with runtime sandboxes mount.
Facts on this page were checked on 26 October 2026.