GuideSandbox

Secrets & Environment Variables

Pass credentials and configuration into sandboxes without hardcoding values

Sandboxes often need credentials — API keys, database URLs, tokens — to perform real work. There are several ways to get those values in safely.

The CUA_API_KEY environment variable

The Sandbox SDK reads your Cua API key from the CUA_API_KEY environment variable. Set it in your shell before running scripts:

export CUA_API_KEY="sk_cua-..."

Or use a .env file with your preferred loader:

# .env
CUA_API_KEY=sk_cua-...
from dotenv import load_dotenv
load_dotenv()

from cua import Sandbox, Image

You can also pass the key explicitly if you manage it programmatically:

async with Sandbox.ephemeral(Image.linux(), api_key=my_key) as sb:
    ...

Passing secrets into the sandbox at runtime

The recommended pattern is to read secrets from the host environment and inject them into the sandbox via sb.shell.run, not via Image.env().

import os
import asyncio
from cua import Sandbox, Image

async def main():
    db_url = os.environ["DATABASE_URL"]  # read from host
    gh_token = os.environ["GITHUB_TOKEN"]

    async with Sandbox.ephemeral(Image.linux()) as sb:
        # Set inside the sandbox for this session only
        await sb.shell.run(f"export DATABASE_URL='{db_url}'")
        await sb.shell.run(f"export GITHUB_TOKEN='{gh_token}'")
        await sb.shell.run("python /app/main.py")

asyncio.run(main())

For multi-command sessions, write a wrapper script instead of exporting in each call:

script = f"""
export DATABASE_URL='{db_url}'
export GITHUB_TOKEN='{gh_token}'
python /app/main.py
"""
result = await sb.shell.run(script)

Image.env() — bake-in non-secret config

Use .env() on the Image builder for configuration that isn't sensitive — feature flags, log levels, app settings:

from cua import Image

img = (
    Image.linux()
    .apt_install("python3")
    .env(
        LOG_LEVEL="info",
        APP_ENV="production",
        PORT="8080",
    )
)

.env() values are stored in the Image spec and visible to anyone who can inspect it. Do not use .env() for API keys, passwords, or tokens.


Copying secret files into the sandbox

For credentials stored as files (SSH keys, service account JSON, certificates):

async with Sandbox.ephemeral(Image.linux()) as sb:
    # Read the file on the host and write it in the sandbox
    with open(os.path.expanduser("~/.ssh/id_rsa")) as f:
        key_content = f.read()

    await sb.shell.run(f"mkdir -p /root/.ssh && chmod 700 /root/.ssh")
    await sb.shell.run(f"cat > /root/.ssh/id_rsa << 'EOF'\n{key_content}\nEOF")
    await sb.shell.run("chmod 600 /root/.ssh/id_rsa")

Alternatively, use Image.copy() for files that are safe to bake into the image:

img = Image.linux().copy("./app-config.json", "/app/config.json")

Best practices

DoDon't
Read secrets from host environment variablesHardcode secrets in Python source
Inject secrets at runtime via sb.shell.runStore secrets in Image.env()
Use .env files + python-dotenv locallyCommit .env files to version control
Use your CI/CD provider's secret managerLog or print secret values

Was this page helpful?