---
title: "Secrets and test keys"
description: "What Bugbearer generates, what you supply, which keys it refuses, and how it protects the values."
---

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

# Secrets and test keys

An app under test needs environment variables. Bugbearer provides what it can. You supply the rest as test keys.

## What Bugbearer provides

Setup matches each variable name against a set of rules.

| Variable kind | What the app gets |
| --- | --- |
| Database (`DATABASE_URL`, Redis, Mongo and similar) | A private database that Bugbearer starts |
| App URLs (`BASE_URL`, `APP_URL` and similar) | The address the test browser uses |
| Auth and session secrets (`AUTH_SECRET`, `JWT_SECRET`, `SESSION_SECRET` and similar) | A random value, generated once per app |
| Email (SMTP, Resend, SendGrid, Postmark, Mailgun and similar) | A test inbox |
| Analytics and error tracking (PostHog, Sentry, Mixpanel and similar) | Left empty, so test traffic stays out |

Any other variable that the app reads is marked **Used**: the value you give reaches the app's container only. Variables the app does not read are ignored.

## What you supply

Third-party keys, such as a payment provider's test key, come from you. On the setup review screen:

- Select **Paste a .env file**, then **Parse on the server**. Or type each value in its own field.
- A variable with no value shows **Needs a value**.

The server parses the file. The agents never see the values.

## Live keys are refused

Bugbearer refuses a value that looks like a live or production credential. It drops the value and marks the row **Refused**. Use a test-mode key instead.

- Stripe live keys (`sk_live_`, `rk_live_`, `pk_live_`) and webhook secrets (`whsec_`)
- Other `sk-live-`, `pk-live-`, `sk_prod_` and `rk_prod_` keys
- Values that are `live`, `prod` or `production`, then `_` or `-`, then 16 or more letters and digits
- AWS access key IDs (`AKIA…`)
- Slack `xoxb-`, `xoxp-`, `xoxa-` and `xoxs-` tokens
- GitHub `ghp_`-style tokens
- OpenAI admin keys
- A `postgres://` URL whose host is not local (`localhost`, `127.0.0.1`, `db`, a `.local` name or a name with no dot). Bugbearer starts its own database.

## How values are protected

- Values are encrypted at rest.
- Values reach the app's container only.
- Bugbearer replaces known secret values with `{{secret:NAME}}` in the boot output that the setup agent sees and in stored logs. It also masks sign-in codes.
- During a test run, the runner removes your stored values from its output.

## Model provider keys

An app that calls a model needs its own key. These names are treated as your keys, not Bugbearer's:
`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, `GOOGLE_GENERATIVE_AI_API_KEY`, `GROQ_API_KEY`, `MISTRAL_API_KEY`, `OPENROUTER_API_KEY`, `XAI_API_KEY` and `AZURE_OPENAI_API_KEY`.

> **Tip**
>
> Create a separate project key for Bugbearer, with a spend limit. Test runs call the model, and agents may trigger those calls many times.

Without a key, the app boots with a placeholder value, so an app that checks its key at start still runs. The review screen shows **Needs your model key**. Model calls in the app get a 401. Test agents are told that model features are unavailable and not to report their failures as bugs.

## Send values with an agent

An agent that holds `bugbearer:env` sends values with the `set_env` tool. No value goes into the conversation, a tool input or a tool result.

1. The agent calls `set_env` with the `appId`. It takes no other input except `mode`.
2. The result holds a `curl` command with a one-use token. The token expires after 15 minutes. A new `set_env` call for the same app revokes the earlier unused token.
3. You write the values in an env file with test-mode keys.
4. The agent runs the command in a shell and uses the path of your file. It does not read, print or open the file.
5. The reply lists each name with a decision: `stored`, `ours`, `replaced`, `left_empty`, `ignored` or `refused`. It never lists a value.
6. If the saved boot plan does not read a stored name, the reply lists it in `notInPlan` and gives a `next` step. The app gets the value only after the plan uses `{{user:NAME}}`. The agent changes the plan with `propose_boot_plan` and `validate_boot_plan`, or calls `start_setup` so the setup agent changes it.
7. The agent calls `list_env_status` to check which names are stored, which are missing, and which the plan reads (`inPlan`).

An upload has these limits: 256 KB, 200 names and 5000 characters per value. Bugbearer applies the same rules as the review screen. It refuses live keys and marks the row `refused`. If a setup agent is running, it receives the names and decisions. Otherwise a saved boot plan boots again.

The agent can call `set_env` with `mode: "link"`. The result is the address of the setup review screen. You open it while you are signed in and type the values there. The environment list appears after setup writes a boot plan.

`answer_setup_question` refuses any text with a `KEY=value` assignment. Never put a value in a reply to the setup agent.

> **Note**
>
> The MCP server is not live in production yet. See [Connect the MCP server](https://docs.bugbearer.com/onboarding-mcp).

Source: https://docs.bugbearer.com/secrets-and-test-keys/index.mdx
