JuliusBrussee/caveman · error
cave_sandbox_credential_env_not_allowlisted
cave_sandbox_credential_env_not_allowlisted
Error message
cave_sandbox_credential_env_not_allowlisted
What it means
Thrown by validateSandboxCredentialEnv() (also called from buildSandboxToolEnv) when an environment variable name is not on the provider allowlist, or is explicitly denied. The sandbox child env is an exact allowlist — not a process.env spread — so only names mapped to a single provider capability in SANDBOX_CREDENTIAL_ENV_TO_CAPABILITY pass; deny-listed families (AWS_, GCP_, GITHUB_, CAVE_, PG, POSTGRES_, ...) and names (PATH, HOME, NODE_OPTIONS, ...) never pass. The offending name is deliberately kept out of the error to avoid leaking secret-identifying names.
Source
Thrown at packages/agent/src/runtime.ts:601
"PATH",
"PWD",
"SHELL",
"DYLD_INSERT_LIBRARIES",
]);
export function validateSandboxCredentialEnv(names: readonly string[]): void {
const capabilities = new Set<SandboxCredentialCapability>();
for (const name of names) {
const denied = typeof name === "string" &&
(SANDBOX_CREDENTIAL_DENY_NAMES.has(name) ||
SANDBOX_CREDENTIAL_DENY_PREFIXES.some((prefix) => name.startsWith(prefix)));
const capability = denied || typeof name !== "string"
? undefined
: SANDBOX_CREDENTIAL_ENV_TO_CAPABILITY.get(name);
if (capability === undefined) {
// Keep profile-controlled names out of errors. This is a policy result,
// not a diagnostic surface, and the name may itself identify a secret.
throw new Error("cave_sandbox_credential_env_not_allowlisted");
}
capabilities.add(capability);
}
if (capabilities.size > 1) {
throw new Error("cave_sandbox_credential_capability_ambiguous");
}
}
/** Build the complete environment for an isolated tool child. No spread of
* `process.env`: only deterministic runtime baseline plus an exact provider
* capability selected by the validated live profile. */
export function buildSandboxToolEnv(names: readonly string[] = []): NodeJS.ProcessEnv {
validateSandboxCredentialEnv(names);
const env: NodeJS.ProcessEnv = {
LANG: process.env.LANG ?? "C",
LC_ALL: process.env.LC_ALL ?? "C",
PATH: process.env.PATH ?? "",
TZ: process.env.TZ ?? "UTC",View on GitHub (pinned to 27d5a3981a)
Solutions
- Use only the provider credential names the framework allowlists (check the SANDBOX_CREDENTIAL_ENV_BY_CAPABILITY map in packages/agent/src/runtime.ts) — one provider's names per call
- If your name is denied because it belongs to a high-impact family (AWS_, GCP_, DATABASE_, ...), do not forward it: restructure the tool to receive credentials via the supported provider capability instead
- Remove non-string/empty entries and typos from the names array; validate names against the exported allowlist before calling buildSandboxToolEnv
Example fix
// before buildSandboxToolEnv(['AWS_SECRET_ACCESS_KEY', 'MY_TYPO_TOKENN']); // after buildSandboxToolEnv(allowlistedProviderNames); // e.g. the single-provider names from SANDBOX_CREDENTIAL_ENV_BY_CAPABILITY
Defensive patterns
Strategy: validation
Validate before calling
const ALLOWLISTED = new Set(Object.values(SANDBOX_CREDENTIAL_ENV_BY_CAPABILITY).flat()); // import/replicate the provider map
function validateCredentialNames(names: readonly unknown[]): string[] {
return names.map((n) => {
if (typeof n !== 'string' || !ALLOWLISTED.has(n)) throw new Error('credential env name is not on the sandbox allowlist');
return n;
});
} Type guard
function isAllowlistedCredentialName(value: unknown): value is string { return typeof value === 'string' && ALLOWLISTED.has(value); } // ALLOWLISTED mirrors SANDBOX_CREDENTIAL_ENV_TO_CAPABILITY keys Try / catch
try { buildSandboxToolEnv(names); } catch (e) { if (e instanceof Error && e.message === 'cave_sandbox_credential_env_not_allowlisted') throw new SandboxConfigError('one or more env names are denied/not allowlisted; check the provider map', { cause: e }); throw e; } Prevention
- Source sandbox env names only from the framework's provider capability map, never from user config
- Never forward cloud/infra credential families (AWS_, GCP_, DATABASE_, ...) into tool children
- Treat the opaque error as intentional: it hides names that may identify secrets
When it happens
Trigger: Passing credential env names such as 'AWS_SECRET_ACCESS_KEY', 'GITHUB_TOKEN', 'ANTHROPIC_API_KEY'-adjacent CAVE_/provider-reserved names, 'PATH', 'HOME', or any string not present in the provider capability map; also any non-string entry in the names array.
Common situations: Trying to hand a sandboxed live tool a cloud credential by env name; copy-pasting a docker-run -e style list of env names into the sandbox profile; assuming any env var present in the parent shell is forwardable to the tool child.
Related errors
- cave_sandbox_conformance_failed
- cave_sandbox_credential_capability_ambiguous
- cave_sandbox_credential_missing
- cave_budget_denomination_unavailable
- probe returned false
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/c81cf82cc6836974.
Report an issue: GitHub.