Repository navigation
Description
Description
Two provider loaders copy a stored credential out of auth.json and assign it into process.env. Once that happens the secret is part of the process environment for the rest of the run, so it is inherited by every child process opencode spawns and appears anywhere the environment is dumped.
packages/opencode/src/provider/provider.ts, amazon-bedrock:
const awsBearerToken = iife(() => {
const envToken = process.env.AWS_BEARER_TOKEN_BEDROCK
if (envToken) return envToken
if (auth?.type === "api") {
process.env.AWS_BEARER_TOKEN_BEDROCK = auth.key
return auth.key
}
return undefined
})sap-ai-core, same shape:
const envServiceKey = iife(() => {
const envAICoreServiceKey = process.env.AICORE_SERVICE_KEY
if (envAICoreServiceKey) return envAICoreServiceKey
if (auth?.type === "api") {
process.env.AICORE_SERVICE_KEY = auth.key
return auth.key
}
return undefined
})Both are the only two process.env[...] = <credential> assignments in that file.
Why it matters
auth.json is written 0600 precisely because its contents are secret. Assigning a value into process.env moves it into a place with none of those properties:
- Inherited by children. Every process opencode spawns gets it — the
bashtool's shells, MCP servers, git subprocesses, hooks. A credential scoped to one provider becomes ambient to every subprocess in the session. - Visible to anything that reads the environment.
/proc/<pid>/environfor same-user processes, crash and diagnostic dumps, and any tool that prints its environment. - Not what the user configured. A key supplied through
auth loginis stored in a0600file; the user has no indication it will also be exported into the environment of unrelated subprocesses.
The comment above the bedrock block shows the assignment is a deliberate workaround, not an oversight:
// TODO: Using process.env directly because Env.set only updates a process.env shallow copy,
// until the scope of the Env API is clarified (test only or runtime?)So the intent was to make the value visible to the AWS SDK, and the process-wide write is the side effect. The value is already returned from the iife and used directly, so the assignment exists only to reach an SDK that reads the environment.
Suggested fix
Pass the credential to the SDK explicitly instead of exporting it. The AWS SDK accepts a bearer token through its client config, and both call sites already hold the value in a local, so the process.env write can be dropped rather than replaced. If a specific SDK path genuinely can only read the environment, scoping the variable to the child that needs it — rather than the whole process — keeps the blast radius to that call.
Resolving the Env.set question named in the TODO would cover both providers at once.
Steps to reproduce
- Configure
amazon-bedrockwith an API key (auth login), soauth.jsonholds{"type":"api","key":"..."} - Start a session and have a model request load the provider
- Use the
bashtool to print the environment
AWS_BEARER_TOKEN_BEDROCK is present in the child shell, holding the key from auth.json. Same for AICORE_SERVICE_KEY with sap-ai-core.
Additional context
Found while auditing which code paths consume a stored provider key, for a plugin that serves credentials from an external secret store. The env-assignment behaviour is independent of that work — it affects any user with a stored API key for either provider.
Severity is bounded: it requires an already-configured provider, and reading it needs same-user access or a dump that includes the environment. It is a hardening issue rather than a remote vulnerability, but the fix looks small.
OpenCode version
dev
Activity
github-actions commentedon Sep 2, 2026
This issue might be a duplicate of existing issues. Please check:
/connectare not applied to a running server (SAP AI Core, GitHub Copilot), and SAP multi-line keys are stored truncated #46354: Covers the sameprocess.env.AICORE_SERVICE_KEYandAWS_BEARER_TOKEN_BEDROCKwrite-once caching behaviour (Bug B in that report) for both SAP AI Core and amazon-bedrock providers, including the stale-value problem it causes.process.env— a downstream effect of the same env-pollution described here.The security/hardening angle in this issue is distinct from #46354's focus on credential refresh, and the two reports complement each other, but the root cause code paths overlap substantially. It may be worth coordinating or consolidating the fix.
opencodejr commentedon Oct 28, 2026
Thanks for the detailed write-up!
The code you quoted (
packages/opencode/src/provider/provider.ts, with theiifeblocks and theEnv.setTODO) is from OpenCode v1 (opencode-ai, versions 0.x/1.x). That file isn't on the currentdevbranch, which is now v2 (@opencode/cli). v1 only gets fixes for critical bugs, and as you note this is a hardening issue with bounded severity, so it's unlikely to be changed in v1. We'd encourage upgrading to v2.How v2 compares:
AWS_BEARER_TOKEN_BEDROCKintoprocess.env. The Bedrock providers inpackages/ai/src/providers/amazon-bedrock*.tstake the key asapiKeyand only read the env var as a fallback.serviceKeyprovider option intoprocess.env.AICORE_SERVICE_KEY(packages/core/src/plugin/provider/sap-ai-core.ts), and a test covers that behaviour. If that matters to you, please open a separate issue against v2 for that path.If you think this is critical, or you can reproduce the Bedrock leak on a v2 release (
opencode --version2.x), please reply here with the details.opencodejr commentedon Oct 29, 2026
Closing this as not planned. The code it describes (
packages/opencode/src/provider/provider.ts) is OpenCode v1, which only gets critical fixes, and we haven't heard that this is critical or that it happens on v2.In v2, Bedrock no longer writes
AWS_BEARER_TOKEN_BEDROCKintoprocess.env. If the SAP AI CoreserviceKey→AICORE_SERVICE_KEYcopy in v2 concerns you, please open a new issue against v2 for it. Thanks again for the careful audit!