# Secrets in Vercel Sandbox

Vercel Sandbox runs Firecracker microVMs you create from your own code, so
seekrit resolves in that code and hands the microVM only what it needs. It also
has the one feature that makes the no-credential shape genuinely enforceable:
`networkPolicy: 'deny-all'`.

## Inject at creation

```ts
import { Sandbox } from '@vercel/sandbox';
import { Seekrit } from '@seekrit/sdk';

const secrets = await new Seekrit({ token: process.env.SEEKRIT_TOKEN }).resolve();

const sandbox = await Sandbox.create({
  env: {
    OPENAI_API_KEY: secrets.OPENAI_API_KEY,
    TAVILY_API_KEY: secrets.TAVILY_API_KEY,
  },
});
```

`env` sets the defaults for every command the sandbox runs. Named keys, not
`env: secrets` — see [Pick names, not the whole
environment](/docs/guides/sandboxes#pick-names-not-the-whole-environment).

## Inject per command

Per-command `env` overrides the creation-time defaults, which is how you keep a
key out of the steps that do not need it:

```ts
await sandbox.runCommand({
  cmd: 'node',
  args: ['summarize.js'],
  env: { OPENAI_API_KEY: secrets.OPENAI_API_KEY },
});

// No key in this one.
await sandbox.runCommand({ cmd: 'node', args: ['render.js'] });
```

> **Note:** `Sandbox.fork()` copies the source sandbox's environment variables into the new one, so a forked sandbox inherits any key you injected. Pass `env` on the fork to override them, and remember that a persistent sandbox auto-snapshots its configuration on stop, so the values come back on resume.

## Keep the credential outside the microVM

This is the shape to use for agent output, and Vercel Sandbox makes it
enforceable rather than advisory. Create the sandbox with **no egress at all**,
then give it one route out — the proxy:

```ts
const sandbox = await Sandbox.create({
  networkPolicy: 'deny-all',
  env: {
    // A placeholder, not a key. Worthless if it leaks.
    OPENAI_API_KEY: '{{seekrit:OPENAI_API_KEY}}',
    OPENAI_BASE_URL: 'https://proxy.internal.example/openai',
  },
});
```

```toml
# seekrit-proxy.toml — wherever you run the proxy, never in the sandbox
[[route]]
prefix = "/openai"
upstream = "https://api.openai.com"
allow = ["OPENAI_API_KEY"]
methods = ["POST"]
paths = ["/v1/chat/completions", "/v1/embeddings"]
```

Why this combination is stronger than either half:

- **`deny-all` makes the proxy the only way out.** Elsewhere an
  `OPENAI_BASE_URL` pointing at the proxy is a suggestion the agent can ignore by
  calling `api.openai.com` directly — with a placeholder that fails, but a
  *stolen* key would work. With no egress, there is nothing to fall back to.
- **The allowlist makes the route narrow.** Even through the proxy, the key
  reaches one upstream, one method, two paths. An agent that decides to spend
  your model budget on a different endpoint is refused, and the refusal is
  logged.
- **The microVM holds no seekrit token**, so a compromise yields a placeholder
  string and a URL.

> **Warning:** `deny-all` blocks the sandbox's package installs too. Bake dependencies into a [custom image](https://vercel.com/docs/sandbox/concepts/images) rather than installing at runtime — and if you widen the network policy to reach a registry, the argument above weakens by exactly the reach you added back.

## See also

- [Agent sandboxes](/docs/guides/sandboxes) — the two shapes and when each is right
- [Agent proxy](/docs/guides/agent-proxy) — the full proxy configuration
- [Agent access policy](/docs/guides/agent-proxy/policy) — publishing the allowlist from the dashboard instead of a file
- [Sync to Vercel](/docs/guides/third-party-sync/vercel) — for a Vercel *deployment*, which is the other problem
