> ## Documentation Index
> Fetch the complete documentation index at: https://docs.superserve.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Bind secrets to a sandbox

> Map secrets to environment variables at sandbox creation. Code in the sandbox reads the env var; the platform attaches the real value to outbound requests.

Bind secrets when you create a sandbox with the `secrets` option — a map of **environment variable → secret name**:

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
  import { Sandbox } from "@superserve/sdk"

  const sandbox = await Sandbox.create({
    name: "research-agent",
    secrets: {
      ANTHROPIC_API_KEY: "anthropic-prod",
      GITHUB_TOKEN: "github-token",
    },
  })
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
  from superserve import Sandbox

  sandbox = Sandbox.create(
      name="research-agent",
      secrets={
          "ANTHROPIC_API_KEY": "anthropic-prod",
          "GITHUB_TOKEN": "github-token",
      },
  )
  ```
</CodeGroup>

Inside the sandbox, `ANTHROPIC_API_KEY` is set like any environment variable — but its value is a **stand-in token**, not your real key. Code in the sandbox uses it normally:

```bash theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
# Inside the sandbox — the code has no idea it's not the real key.
curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -d '{ ... }'
```

The request leaves the sandbox, the platform swaps the stand-in token for your real credential on the way to `api.anthropic.com`, and Anthropic sees the real key. If code in the sandbox prints `$ANTHROPIC_API_KEY`, dumps its environment, or leaks it some other way, all it has is the stand-in token — worthless anywhere except authenticated requests to the secret's hosts.

## Attach and detach on a running sandbox

You can also change a sandbox's bindings after it exists — useful when an agent session is already up and needs a new credential, or when you want to remove one. Works on `active` and `paused` sandboxes.

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
  // Add a binding.
  await sandbox.attachSecret("ANTHROPIC_API_KEY", "anthropic-prod")

  // Remove it later.
  await sandbox.detachSecret("ANTHROPIC_API_KEY")
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
  # Add a binding.
  sandbox.attach_secret("ANTHROPIC_API_KEY", "anthropic-prod")

  # Remove it later.
  sandbox.detach_secret("ANTHROPIC_API_KEY")
  ```
</CodeGroup>

A binding takes effect for **processes started after** the call — a process already running keeps the environment it started with until it re-execs. Detaching cuts the credential's access for new processes immediately and for an already-running process within about a minute. A `paused` sandbox applies either change when it resumes.

## Inspecting bindings

A sandbox reports the secrets bound to it:

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
  for (const b of sandbox.secrets ?? []) {
    console.log(b.envKey, "←", b.secretName, b.revoked ? "(revoked)" : "")
  }
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
  for b in sandbox.secrets or []:
      print(b.env_key, "←", b.secret_name, "(revoked)" if b.revoked else "")
  ```
</CodeGroup>

`revoked` flips to `true` when the underlying secret has been deleted — the env var still holds the (now-inert) stand-in token, and any request that relies on it fails rather than falling back to a stale credential.

To go the other way — from a secret to the sandboxes using it — see [`getSandboxes()`](/secrets/audit#sandboxes-using-a-secret).

<Note>
  `secrets` and [`envVars`](/sandbox/environment-variables) both set environment variables, so a given name can come from one or the other — not both. Reusing the same name across them is rejected.
</Note>

## Combine with network rules

Secrets pair naturally with [network rules](/sandbox/networking): attach the credential *and* restrict the sandbox to only the hosts it should reach. A sandbox that can authenticate to `api.anthropic.com` and reach nothing else is hard to misuse.

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
  const sandbox = await Sandbox.create({
    name: "locked-down",
    secrets: { ANTHROPIC_API_KEY: "anthropic-prod" },
    network: {
      allowOut: ["api.anthropic.com"],
      denyOut: ["0.0.0.0/0"],
    },
  })
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
  from superserve import NetworkConfig

  sandbox = Sandbox.create(
      name="locked-down",
      secrets={"ANTHROPIC_API_KEY": "anthropic-prod"},
      network=NetworkConfig(
          allow_out=["api.anthropic.com"],
          deny_out=["0.0.0.0/0"],
      ),
  )
  ```
</CodeGroup>
