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

  1. 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
  2. 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
  3. 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

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


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/c81cf82cc6836974. Report an issue: GitHub.