> ## Documentation index
> Fetch the complete documentation index at: https://upstash.com/docs/llms.txt
> Ask it with GET https://upstash.com/docs/ask?q=<keywords or question>. Short keywords rank best.
> Use these to discover all available pages before exploring further.
> Feature requests: https://upstash.com/docs/common/help/feature-requests.md lists what users asked for and how to vote for a request or add one.
> Page rating: `GET https://upstash.com/docs/feedback?path=/docs/box/overall/security&helpful={true|false}&comment={comment}` records whether this page helped. The `comment` (URL-encoded, at most 500 characters) says what helped, or what was missing or wrong; a `helpful=false` rating needs it. It is anonymous and needs no key. Comments hold no code, secrets or personal data.

# Security & Secrets

## Isolation

Every Upstash Box runs in its own isolated container with a dedicated filesystem, process tree, and network stack. Boxes cannot communicate with or observe each other. Network access is restricted — containers cannot reach private networks, cloud metadata services, or other internal infrastructure.

## Environment Variables

You can pass environment variables when creating a box. These are available to all code running inside the box, including your agent and any user-submitted code.

<CodeGroup>
```typescript box.ts
const box = await Box.create({
  runtime: "node",
  env: {
    DATABASE_URL: "postgres://...",
    ANTHROPIC_API_KEY: "sk-ant-...",
  },
})
```

```python box.py
box = Box.create(
    runtime="node",
    env={
        "DATABASE_URL": "postgres://...",
        "ANTHROPIC_API_KEY": "sk-ant-...",
    },
)
```
</CodeGroup>

<Warning>
Environment variables are visible to all code running inside the box. If you run untrusted code, those secrets can be read by the untrusted code. For sensitive credentials, use [Attach Headers](/box/overall/attach-headers) instead.
</Warning>

## Attach Headers

For injecting secret HTTP headers into outbound HTTPS requests without exposing them inside the container, see [Attach Headers](/box/overall/attach-headers).

## Read-only API keys

A read-only API key lets a monitoring tool or a debugging agent look into your boxes without being able to change them. Create one in the [console](https://console.upstash.com/box): open **Box**, then on the **Overview** tab under **API Keys** click **+ API Key** and pick **Read Only**. A key's permissions can't be changed later.

With a read-only key you can:

- Get and list boxes, and read status, metrics, logs, schedules, previews and config.
- List, read and download files, and read git status and diffs.
- Run commands with `exec`. They run as a separate user with an empty environment, which can't write to the workspace or read the platform's credential files.

Everything else returns `403 This API key is read-only`: creating, deleting, pausing or resetting boxes, runs, file and git writes, schedules, previews, config changes, streaming exec and terminal sessions. On a paused box, commands and file and git reads return `409` instead of waking it; box details and logs still work.

Secrets are masked: env var values and schedule webhook header values come back as their first four characters followed by `••••`, MCP server headers come back only as those masked previews, and schedule webhook URLs are cut to their scheme and host (`https://example.com/••••`).

<CodeGroup>
```bash CLI
export UPSTASH_BOX_API_KEY=box_...   # read-only key
box list
box exec --box my-box -- 'tail -n 50 /workspace/home/app.log'
```

```typescript box.ts
const box = await Box.get("my-box", { apiKey: process.env.READ_ONLY_BOX_KEY })
const { stdout } = await box.exec.command("tail -n 50 /workspace/home/app.log")
```
</CodeGroup>

<Warning>
A read-only key limits what it can change through the Box API, not what a command can see. Commands still have network access, can read any file in the workspace that isn't private to its owner, and can see other processes' command lines. The startup command and MCP server arguments are returned as written. Keep secrets in env vars or [Attach Headers](/box/overall/attach-headers), not in files, command lines or arguments.
</Warning>

## Browser URLs

Boxes created with [`browser: true`](/box/overall/browser/overview) can hand out two kinds of URLs that carry their access token in the URL itself, so they work without an API key:

- [Live view](/box/overall/browser/live-view) URLs are **view-only**. Frames stream out and no input goes in, but anyone with the URL can watch the tab.
- [CDP](/box/overall/browser/connect) URLs give **full control** of the browser to anyone holding them.

Treat both as secrets and share them only where that level of access is intended. Recording playlist URLs are not tokenized. Fetching them requires your Box API key, like any other API call.

## Blocked Environment Variables

For system security, the following environment variables cannot be set. If you pass them in `env` when creating a box, they are ignored. Saving them as account-level environment variables fails with a `400` error.

| Variable | Reason |
|---|---|
| `PATH` | Prevents binary hijacking |
| `HOME` | Prevents home directory manipulation |
| `LD_PRELOAD` | Prevents shared library injection |
| `LD_LIBRARY_PATH` | Prevents library path hijacking |
| `NODE_OPTIONS` | Prevents Node.js flag injection |
| `UPSTASH_BOX_ID` | Reserved. Set by the platform to the box ID |
| `UPSTASH_BOX_NAME` | Reserved. Set by the platform to the box name |
| `UPSTASH_BOX_AGENT` | Reserved. Set by the platform to the agent harness, when one is configured |
| `UPSTASH_BOX_RUNTIME` | Reserved. Set by the platform to the box runtime |

All other environment variables — including `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, and their `*_BASE_URL` variants — are allowed. The built-in agent runner uses its own isolated environment that overrides these per-run.
