Skip to main content

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.
const box = await Box.create({
  runtime: "node",
  env: {
    DATABASE_URL: "postgres://...",
    ANTHROPIC_API_KEY: "sk-ant-...",
  },
})
Environment variables are visible to all code running inside the box. If you run untrusted code (e.g., user-submitted prompts that execute shell commands), those secrets can be read by the untrusted code. For sensitive credentials, use Attach Headers instead.

Attach Headers

attachHeaders lets you inject HTTP headers into outbound HTTPS requests from a box — without the secrets ever entering the container. This is ideal for passing API keys, tokens, or credentials that should not be accessible to untrusted code.

How it works

When you create a box with attachHeaders, a TLS-intercepting proxy on the host transparently injects the specified headers into outbound HTTPS requests matching the configured host patterns. The secrets exist only on the host — they never appear in environment variables, files, or process memory inside the container. For hosts that don’t match any rule, traffic passes through untouched with no TLS interception.

Usage

const box = await Box.create({
  runtime: "node",
  attachHeaders: {
    "api.stripe.com": {
      Authorization: "Bearer sk_live_...",
    },
    "*.supabase.co": {
      apikey: "eyJ...",
    },
    "api.anthropic.com": {
      "x-api-key": "sk-ant-...",
    },
  },
})
Now any HTTPS request from inside the box to api.stripe.com will automatically include the Authorization header — without the Stripe key being visible anywhere inside the container.
// Code running inside the box — the key is injected transparently
const result = await box.exec.command(
  'curl -s https://api.stripe.com/v1/charges?limit=1'
)
// The Authorization header was added by the proxy — the container never sees the key

Host patterns

PatternMatches
api.stripe.comExact match only
*.supabase.coAny subdomain: xyz.supabase.co, db.supabase.co
  • Patterns must be lowercase
  • Wildcard *. matches any subdomain (most-specific match wins)
  • Only *. prefix wildcards are supported

When to use attachHeaders vs env vars

Environment VariablesAttach Headers
VisibilityVisible to all code in the boxNever enters the container
Use caseNon-sensitive config, or when you trust all code in the boxAPI keys, tokens, credentials for untrusted code
SDK compatibilityWorks with any SDK that reads from envWorks with any SDK that makes HTTPS requests
SetupPass in envPass in attachHeaders with host patterns

Limitations

  • attachHeaders is set once at box creation and cannot be updated
  • Only HTTPS (port 443) traffic is intercepted
  • HTTP/2 connections through matched hosts are downgraded to HTTP/1.1
  • Header values are encrypted at rest and never returned in API responses

Blocked Environment Variables

For system security, the following environment variables cannot be set:
VariableReason
PATHPrevents binary hijacking
HOMEPrevents home directory manipulation
LD_PRELOADPrevents shared library injection
LD_LIBRARY_PATHPrevents library path hijacking
NODE_OPTIONSPrevents Node.js flag injection
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.