env or /proc inside the sandbox.123456789101112131415161718192021222324252627282930import { 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
1234567// 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-...');
1234const store = await SecretStore.create({ name: 'restricted-store', egressAllowlist: ['api.anthropic.com', '*.openai.com'], });
api.anthropic.com) and wildcards (*.openai.com). An empty allowlist means all hosts are allowed.1234567891011// 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);
123456789101112131415161718import { Sandbox, Snapshots, Image } from '@opencomputer/sdk/node'; // Pre-build a reusable snapshot const snapshots = new Snapshots(); await snapshots.create({ name: 'data-pipeline', image: Image.base().aptInstall(['python3-pip']).pipInstall(['pandas']), }); // Create sandboxes from the snapshot, each with their own credentials const worker1 = await Sandbox.create({ snapshot: 'data-pipeline', secretStore: 'worker-1-keys', }); const worker2 = await Sandbox.create({ snapshot: 'data-pipeline', secretStore: 'worker-2-keys', });
123456789101112// Bake a base snapshot with git credentials const base = await Sandbox.create({ secretStore: 'git-creds' }); await base.exec.run('git clone https://github.com/org/repo /app'); const cp = await base.createCheckpoint('repo-cloned'); // Fork with sandbox-specific API credentials (layered on top of git-creds) const worker1 = await Sandbox.createFromCheckpoint(cp.id, { secretStore: 'worker-1-keys', }); const worker2 = await Sandbox.createFromCheckpoint(cp.id, { secretStore: 'worker-2-keys', });
| Property | Detail |
| Encryption at rest | AES-256-GCM in Postgres, key via OPENSANDBOX_SECRET_ENCRYPTION_KEY |
| Never in VM memory | Env vars contain opaque osb_sealed_* tokens |
| Host-side only | Real values exist only in the MITM proxy process on the worker host |
| Egress control | Allowlists restrict which domains receive secrets |
| Per-secret scoping | Individual secrets can be locked to specific hosts |
| Values never returned | The API only returns secret names and metadata, never values |