cyberine
UsageRun recipes

Which secrets a CLI worker sees — generic secret strip and passthrough (kznbp)

T603 and k8rhz scoped provider credentials only, so every other secret in the launching shell reached an auto-approve CLI worker: GITHUBTOKEN, NPMTOKEN, AWSSECRETACCESSKEY, DATABASEURL,...

T603 and k8rhz scoped provider credentials only, so every other secret in the launching shell reached an auto-approve CLI worker: GITHUB_TOKEN, NPM_TOKEN, AWS_SECRET_ACCESS_KEY, DATABASE_URL, STRIPE_SECRET_KEY and the like, and aider / crush / qwen / goose:litellm / an unknown opencode prefix got the whole environment. T603's narrower scope was a task-level choice, not an operator ruling. buildScopedChildEnv() (src/adapters/CliAgentAdapter.ts) now applies two more rules to every spawned CLI worker:

  • Generic secrets are stripped. Any name ending in _TOKEN, _SECRET, _SECRET_KEY, _SECRET_ACCESS_KEY, _PASSWORD, _PASSWD, _DSN or DATABASE_URL (case-insensitive, isWorkerSecretEnvKey) is removed, except a short keep-list: Cyberine's own callback tokens for every worker (CYBERINE_MCP_AUTH_TOKEN for a worker that calls back into cyberine mcp, CYBERINE_BUS_HUB_TOKEN and CYBERINE_API_TOKEN for a team worker's bus client and a remote cyberine call), ANTHROPIC_AUTH_TOKEN for a claude worker (its gateway bearer), and AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, BEDROCK_SECRET_ACCESS_KEY, BEDROCK_SESSION_TOKEN for a Bedrock-routed worker (claude with CLAUDE_CODE_USE_BEDROCK set, a bedrock/ or bedrock_converse/ model for aider / crush, amazon-bedrock/ for opencode, provider aws_bedrock for goose). Names that do not match the pattern are untouched, so SSH_AUTH_SOCK, HTTP_PROXY / HTTPS_PROXY / NO_PROXY (either case), AWS_PROFILE, AWS_ACCESS_KEY_ID, PATH and HOME still reach the worker.
  • A CLI with no allowlist gets only the provider key its model implies. impliedProviderKeysForCli() reads the model string: a <provider>/<model> prefix through the same map as opencode plus moonshot and dashscope (aider:deepseek/deepseek-chat keeps DEEPSEEK_API_KEY only), a bare model name by family (gpt-* / o3 → OPENAI_API_KEY, claude-* / sonnet → ANTHROPIC_API_KEY, gemini* → GEMINI_API_KEY, deepseek* → DEEPSEEK_API_KEY, grok* → XAI_API_KEY), and qwen keeps its three overlapping keys (DASHSCOPE_API_KEY, BAILIAN_CODING_PLAN_API_KEY, OPENAI_API_KEY). When the model names nothing recognizable (aider:default, crush:default, goose:litellm, a custom opencode gateway prefix) the worker keeps every *_API_KEY / *_TOKEN_KEY, because aider's and crush's default model picks itself from whichever key is present; it still loses every *_OAUTH_TOKEN and every generic secret.

Run recipe: nothing to turn on, every spawn applies it. To hand a worker a secret it needs (a gh call inside the worker authenticated by GH_TOKEN, a custom opencode gateway whose key is MYGATEWAY_TOKEN), list the names in the shell or in ~/.cyberine/.env:

export CYBERINE_WORKER_ENV_PASSTHROUGH="GH_TOKEN,MYGATEWAY_TOKEN"
cyberine run "fix the failing release script"

Names are separated by commas or whitespace and must match exactly. The list is read once, when Cyberine loads its config, before the current directory's .env is loaded, so a cloned repo's .env cannot widen it; it is not a config.json key either. It widens only the generic-secret rule: a provider key off the worker's allowlist and every *_OAUTH_TOKEN stay stripped even when listed, so the seat scoping above is unchanged.

The scoping is covered with no network call and no spawn by:

npm run selftest:config-perms-env-scoping
npm run selftest:claude-oauth-token-scoping

Known Limitations and Deferred Work. This is still a denylist with a keep-list, not a strict allowlist: a secret whose name matches none of the suffixes (MY_API_CREDS, a URL with a password in it such as REDIS_URL) still reaches the worker; a strict allowlist was rejected for now because it breaks Bedrock, MCP callbacks, git / gh / ssh-agent and proxies. Bedrock routing for claude is read from CLAUDE_CODE_USE_BEDROCK in the environment Cyberine builds, so a Bedrock switch set only in ~/.claude/settings.json is not seen and the AWS secrets are stripped; add them to CYBERINE_WORKER_ENV_PASSTHROUGH in that setup. A worker that uses gh, npm publish or a database through an env token now fails until the name is passed through; one stored in a keychain or a config file (gh auth login, ~/.npmrc, ~/.aws/credentials) is unaffected by env scoping, and the host sandbox's read deny-list is what guards those files. The bare-model family map is a heuristic: a model it does not know falls back to keeping every provider key. The in-process BedrockAdapter reads process.env directly and is not a spawned worker, so none of this applies to it.