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

# Secrets

> Bind workspace secrets to VMs, scope credential hosts, and rotate values without restarting

VM runtime secrets use a proxy: the guest receives a stable `beam_secret_...` placeholder, and the worker substitutes the real value only in HTTPS request headers sent to approved hosts. The worker verifies upstream TLS and scrubs literal secret values from response headers, bodies, and WebSocket messages.

This applies to sandbox and VM runtime bindings. Ordinary containers/pods, functions, endpoints, task queues, and image builds receive plaintext environment values; adding credential hosts does not enable proxying for those workloads.

## Create and bind a secret

Create a workspace secret with the host that may receive its value:

```bash theme={null}
beam secret create OPENAI_API_KEY "$REAL_OPENAI_API_KEY" --host api.openai.com
```

For an existing secret, add hosts with `beam secret update NAME VALUE --host HOST`. Repeat `--host` for multiple hosts; `*.example.com` matches subdomains but excludes `example.com`. Hosts cannot include schemes, ports, paths, IPs, or CIDRs. Up to 64 host rules are supported.

Bind the secret by name when creating a VM. [Configure SDK authentication](/v2/vm/sdk#installation-and-configuration) before using the SDK examples.

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    beam vm new agentbox --secret OPENAI_API_KEY
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from beam import VM

    vm = VM("agentbox", secrets=["OPENAI_API_KEY"]).create()
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    import { VM } from "@beamcloud/beam-js";

    const vm = await VM.create({
      name: "agentbox",
      secrets: ["OPENAI_API_KEY"],
    });
    ```
  </Tab>
</Tabs>

## Use the credential inside the VM

Read the environment variable normally and pass it directly in an HTTPS header, such as `Authorization` or `x-api-key`:

```bash theme={null}
beam vm exec agentbox -- sh -c \
  'curl -fsS https://api.openai.com/v1/models -H "Authorization: Bearer $OPENAI_API_KEY"'
```

The single quotes keep variable expansion inside the VM. The request leaves the guest with a placeholder; the worker substitutes the real key for `api.openai.com`. On other hosts, the placeholder is never exchanged for the key.

Through [MCP](/v2/operations/mcp#secrets-and-egress), bind names under `create_vm.spec.secrets` or add per-command bindings with `vm_exec.secrets`.

## Combine secrets with network rules

Credential hosts control where secret substitution is allowed. [Outbound network rules](/v2/vm/networking#outbound-network-controls) control which destinations the VM can reach.

| VM network setting | Behavior |
| - | - |
| Default open policy | Other public destinations remain reachable; only approved hosts receive substituted credentials. |
| `--block-network` / `block_network=True` | Only the approved hosts of bound secrets are reachable. |
| Explicit `allow_list` | Its hostname rules must cover every credential host. Secrets do not widen the list; IP/CIDR entries alone do not cover hostnames. |

For a VM that only needs its credential hosts:

```bash theme={null}
beam vm new restricted-agent --secret OPENAI_API_KEY --block-network
```

Do not combine `block_network=True` with an explicit allowlist. Proxied private, loopback, and link-local destinations remain blocked, even with an IP/CIDR rule.

## Rotate a value

```bash theme={null}
beam secret update OPENAI_API_KEY "$NEW_OPENAI_API_KEY"
```

The placeholder stays stable. The next request after the worker's 15-second cache expires uses the new value without restarting the VM. Omit `--host` to preserve existing hosts, supply it to replace them, or use `--clear-hosts` to remove them. A secret without approved hosts cannot be bound as an ordinary brokered runtime secret.

## Compatibility and token opt-ins

* Substitution is literal and header-only, over HTTPS on port 443. Query/body credentials, local signing, hashing, and encoding the placeholder are unsupported. Plain HTTP to a bound credential host is blocked.
* For Basic auth, store the base64 credential as the secret and send `Authorization: Basic $SECRET`; do not encode the placeholder. Certificate-pinned clients cannot use TLS interception.
* The guest receives trusted CA certificates automatically. [Nested Docker containers](/v2/vm/docker) need explicit CA configuration.
* VMs receive no automatic workspace token. Explicit `BETA9_TOKEN` or `BEAM_TOKEN` secret bindings are plaintext opt-ins and do not require hosts.
* Build secrets passed with `--build-secret` expose plaintext values during image builds and do not create runtime bindings. Manually putting a real key in `env` or a file also remains plaintext.

See the [full secrets reference](/v2/environment/secrets#brokered-secrets-for-vms-and-sandboxes) for value limits, WebSocket and response-scrubbing limits, and secret-management commands.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.