Skip to content

[BUG]: amazon-bedrock and sap-ai-core write stored API keys into process.env, leaking them to every child process #46745

Closed as not planned

Description

@iceteaSA

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 bash tool'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>/environ for same-user processes, crash and diagnostic dumps, and any tool that prints its environment.
  • Not what the user configured. A key supplied through auth login is stored in a 0600 file; 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

  1. Configure amazon-bedrock with an API key (auth login), so auth.json holds {"type":"api","key":"..."}
  2. Start a session and have a model request load the provider
  3. Use the bash tool 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

  1. github-actions commented on Sep 2, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    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.

  2. opencodejr commented on Oct 28, 2026

    @opencodejr

    Thanks for the detailed write-up!

    The code you quoted (packages/opencode/src/provider/provider.ts, with the iife blocks and the Env.set TODO) is from OpenCode v1 (opencode-ai, versions 0.x/1.x). That file isn't on the current dev branch, 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:

    • amazon-bedrock: v2 no longer writes AWS_BEARER_TOKEN_BEDROCK into process.env. The Bedrock providers in packages/ai/src/providers/amazon-bedrock*.ts take the key as apiKey and only read the env var as a fallback.
    • sap-ai-core: v2 still copies a configured serviceKey provider option into process.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 --version 2.x), please reply here with the details.

  3. opencodejr commented on Oct 29, 2026

    @opencodejr

    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_BEDROCK into process.env. If the SAP AI Core serviceKey → AICORE_SERVICE_KEY copy in v2 concerns you, please open a new issue against v2 for it. Thanks again for the careful audit!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions