Skip to main content
Secrets let you pass API keys, tokens, and credentials into sandboxes without the real values ever entering the VM. They are encrypted at rest, sealed into opaque tokens at boot, and only revealed by a host-side proxy on outbound HTTPS requests.

How it works

The real secret value only exists in the host-side proxy’s memory — it is never written to disk, never sent to the VM, and never visible via env or /proc inside the sandbox.

Quick start

Create a secret store, add a secret, and launch a sandbox that uses it:
import { Sandbox, SecretStore } from '@opencomputer/sdk';

// 1. Create a secret store with egress restrictions
const store = await SecretStore.create({
  name: 'my-agent-secrets',
  egressAllowlist: ['api.anthropic.com'],
});

// 2. Add an encrypted secret
await SecretStore.setSecret(store.id, 'ANTHROPIC_API_KEY', 'sk-ant-...');

// 3. Create a sandbox — secrets are injected as sealed tokens
const sandbox = await Sandbox.create({
  secretStore: 'my-agent-secrets',
  timeout: 600,
});

// Inside the VM, the env var is sealed — not the real key
const result = await sandbox.exec.run('echo $ANTHROPIC_API_KEY');
console.log(result.stdout); // "osb_sealed_7f3a9c..."

// But HTTPS requests to allowed hosts get the real value via the proxy
const apiResult = await sandbox.exec.run(`
  curl -s https://api.anthropic.com/v1/messages \\
    -H "x-api-key: $ANTHROPIC_API_KEY" \\
    -H "anthropic-version: 2023-06-01" \\
    -H "content-type: application/json" \\
    -d '{"model":"claude-haiku-4-5-20251001","max_tokens":10,"messages":[{"role":"user","content":"hi"}]}'
`);
console.log(apiResult.stdout); // 200 OK — real key was substituted by the proxy

Per-secret host restrictions

You can restrict individual secrets so they are only substituted in requests to specific hosts. This prevents a compromised dependency from exfiltrating secrets to an attacker-controlled server.
// This secret will only be substituted in requests to api.anthropic.com
await SecretStore.setSecret(store.id, 'ANTHROPIC_API_KEY', 'sk-ant-...', {
  allowedHosts: ['api.anthropic.com'],
});

// This secret works on any allowed egress host
await SecretStore.setSecret(store.id, 'GENERIC_TOKEN', 'tok-...');

Egress allowlists

Secret stores can restrict which hosts the sandbox can make HTTPS requests to. Requests to hosts not on the list are blocked by the proxy.
const store = await SecretStore.create({
  name: 'restricted-store',
  egressAllowlist: ['api.anthropic.com', '*.openai.com'],
});
Supports exact matches (api.anthropic.com) and wildcards (*.openai.com). An empty allowlist means all hosts are allowed.

Managing secrets

// List all secret stores
const stores = await SecretStore.list();

// List secrets in a store (metadata only — values are never returned)
const entries = await SecretStore.listSecrets(store.id);

// Delete a secret
await SecretStore.deleteSecret(store.id, 'OLD_KEY');

// Delete a store and all its secrets
await SecretStore.delete(store.id);

Security properties

PropertyDetail
Encryption at restAES-256-GCM in Postgres, key via OPENSANDBOX_SECRET_ENCRYPTION_KEY
Never in VM memoryEnv vars contain opaque osb_sealed_* tokens
Host-side onlyReal values exist only in the MITM proxy process on the worker host
Egress controlAllowlists restrict which domains receive secrets
Per-secret scopingIndividual secrets can be locked to specific hosts
Values never returnedThe API only returns secret names and metadata, never values

Next steps