Runtime

How to use API keys in a sandbox without exposing them

Store the key with runtime secrets set NAME --host api.example.com; sandboxes see a placeholder and Runtime adds the value in transit.

On Runtime the sandbox never holds the key: not in its environment, its memory or its disk, so a prompt injection or a stolen sandbox has nothing to leak. Each secret names the hosts it may go to. The proxy on the host puts the value into HTTPS requests to those hosts and nowhere else, and code that sends the placeholder anywhere else sends something worthless. One stored secret serves every sandbox of the account, with up to 50 secrets per account.

Store a secret

Terminalprintf %s "$OPENAI_API_KEY" | runtime secrets set OPENAI_API_KEY --host api.openai.comruntime secrets ls

The CLI reads the value from standard input only, so it never lands in your shell history, and typed at a terminal it is not shown. ls shows names, hosts and placeholders, never values.

TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.secrets.set("OPENAI_API_KEY", {  value: process.env.OPENAI_API_KEY ?? "",  hosts: ["api.openai.com"],});
Pythonimport osfrom withruntime import Runtimeruntime = Runtime()runtime.secrets.set("OPENAI_API_KEY", value=os.environ.get("OPENAI_API_KEY", ""),                    hosts=["api.openai.com"])

An agent connected through MCP uses runtime_secrets_set, runtime_secrets_list and runtime_secrets_delete.

Use it from code in the sandbox

Nothing changes in the code. Every sandbox has an environment variable of the secret's name, holding a placeholder such as rtsec_3f9c…, and an SDK that reads OPENAI_API_KEY sends it as usual:

TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create();const call = await sbx.exec(  'curl -sS https://api.openai.com/v1/models -H "Authorization: Bearer $OPENAI_API_KEY"',  { timeoutMs: 30_000 },);console.log(call.exitCode);const seen = await sbx.exec("printenv OPENAI_API_KEY");console.log(seen.stdout); // rtsec_…, the placeholder, never the key
Pythonfrom withruntime import Sandboxwith Sandbox.create() as sbx:    call = sbx.exec('curl -sS https://api.openai.com/v1/models '                    '-H "Authorization: Bearer $OPENAI_API_KEY"', timeout_ms=30_000)    print(call.exit_code)    print(sbx.exec("printenv OPENAI_API_KEY").stdout)  # the placeholder

Set the header for the code

With header, the proxy sets that header on every HTTPS request to the hosts, replacing one the sandbox sent, so code needs no placeholder at all. format says where the value goes:

Terminalruntime secrets set GITHUB_TOKEN --host api.github.com --header Authorization --format 'token {value}' < token.txt
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.secrets.set("GITHUB_TOKEN", {  value: process.env.GITHUB_TOKEN ?? "",  hosts: ["api.github.com", "*.githubusercontent.com"],  header: "Authorization",  format: "token {value}",});

A secret with header Authorization and format AWS4-HMAC-SHA256 {value} holds a bucket's ACCESS_KEY_ID:SECRET_ACCESS_KEY and signs S3 requests again with the real key, so the secret key is never sent at all (mount your own bucket).

Limits

What Limit
Secrets per account 50
Value At most 8 KiB of visible ASCII
Hosts per secret 16, as names or *.domain
Where it is added URL and headers of HTTPS requests to the secret's hosts
Never added Plain HTTP, request bodies, any other host
Protocol to its hosts HTTP/1.1, WebSockets included; gRPC works to every other host
Replacing a value Keeps the placeholder; running sandboxes use it within seconds

Mistakes and how Runtime handles them

  • Passing the key in env or the command line. env values are never echoed back and journals keep only a hash, but the sandbox then holds the key. A command line is recorded as sent. Use a secret instead.
  • Naming a host that echoes requests. A host that reflects headers back would show the value to the sandbox. Name only hosts you trust with it.
  • A program with pinned certificates. The proxy opens the HTTPS connection to the secret's hosts itself and checks the real server's certificate. Python, Node, curl and git already trust Runtime's certificate through SSL_CERT_FILE, REQUESTS_CA_BUNDLE and NODE_EXTRA_CA_CERTS; a program with its own list needs /usr/local/share/ca-certificates/runtime-egress.crt added to it.
  • Deleting to revoke. runtime secrets rm erases the value on Runtime; it does not revoke the key at its provider. Rotate it there too.
  • A database password. Only HTTPS requests are rewritten, so a Postgres password cannot be swapped this way. For your own cloud, an identity token avoids storing a key at all.

Lock it down further

A secret stops the key from leaking; network rules stop the data. Allow only the secret's host and the sandbox can call that API and nothing else. For no network at all, turn the internet off.

Facts on this page were checked on 25 September 2026.