Skip to content

fix(orchestrator): gateway mode leaked raw provider key to opencode sub-agents via OPENCODE_CONFIG_CONTENT - #11850

Merged
lalalune merged 1 commit into
developfrom
fix/gateway-opencode-config-leak
Jul 3, 2026
Merged

fix(orchestrator): gateway mode leaked raw provider key to opencode sub-agents via OPENCODE_CONFIG_CONTENT#11850
lalalune merged 1 commit into
developfrom
fix/gateway-opencode-config-leak

Conversation

@NubsCarson

Copy link
Copy Markdown
Member

Gateway mode leaked the raw provider key to opencode sub-agents (and opencode bypassed the gateway)

Defect

86bc107 (#11651, gateway mode for #11536 E2) states the invariant: with ELIZA_MODEL_GATEWAY_URL + ELIZA_MODEL_GATEWAY_TOKEN set, a child env dump contains no raw provider key. An agentType: "opencode" spawn broke that invariant twice over:

  1. Raw key leak. AcpService.buildEnv's opencode block calls buildOpencodeAcpEnvbuildOpencodeSpawnConfig (opencode-config.ts), which embeds the raw CEREBRAS_API_KEY / ELIZA_OPENCODE_API_KEY / Eliza Cloud key as provider.*.options.apiKey inside the JSON assigned to env.OPENCODE_CONFIG_CONTENT. applyModelGatewayEnv (model-gateway.ts) runs after it and deletes only the seven named env keys — it never touches OPENCODE_CONFIG_CONTENT — so the raw key rides into the child env inside the JSON blob.
  2. Gateway bypass. The same config points the opencode child's baseURL straight at api.cerebras.ai / Eliza Cloud, so its model traffic skips the gateway entirely.

Deleting the key env vars earlier would not have fixed this: opencode-config's setting() falls back to runtime settings and config-env, so the key gets embedded regardless of env deletion order (multi-account pool rotation also injects CEREBRAS_API_KEY for opencode through this same read). model-gateway-env.test.ts only exercised agentType: "claude" | "codex", which is why the gap was invisible.

Fix (structural)

  • buildOpencodeSpawnConfig checks resolveModelGatewayConfig() FIRST — before any credential read from any source. In gateway mode it returns a gateway-pointed @ai-sdk/openai-compatible provider config (baseURL = gateway URL, apiKey = gateway token): there is nothing raw to leak, and the opencode child's traffic goes through the gateway — the same transport contract OPENAI_BASE_URL/ANTHROPIC_BASE_URL gives the codex/claude children. Provider auto-detection and custom base URLs are deliberately ignored in gateway mode (gateway centralizes egress); model names pass through unchanged, defaulting to the same chain the direct cerebras-api path uses.
  • applyModelGatewayEnv now enforces the stated invariant literally: raw values captured from the named keys are swept out of every remaining env value, so any composite carrier (a JSON blob like OPENCODE_CONFIG_CONTENT) that still embeds a raw key is dropped whole. Fail-closed backstop for future merge steps; the opencode path never trips it now that the config is gateway-built.

Off-mode behavior is byte-identical: the gateway branch is dead code when either var is unset, and a new off-mode spawn test pins the legacy direct-cerebras wiring (raw key embedded, no gateway URLs) exactly as before.

Evidence

Defect re-confirmed — new tests against the previous code (7 fail):

FAIL  model-gateway-env.test.ts > gateway mode ON — spawned sub-agent env >
      opencode spawn: OPENCODE_CONFIG_CONTENT routes through the gateway, raw keys excluded
AssertionError: expected undefined to be 'https://gateway.test.invalid/v1'
  (child env kept the direct-cerebras config with the raw key instead)

FAIL  model-gateway-env.test.ts > applyModelGatewayEnv (pure env rewrite) >
      scrubs composite env values that embed a raw provider key (fail closed)
+ Received: "{\"provider\":{\"cerebras\":{\"options\":{\"apiKey\":\"csk-raw-cerebras-DO-NOT-LEAK\"}}}}"
  (raw key survived applyModelGatewayEnv inside OPENCODE_CONFIG_CONTENT)

+ 5 gateway-branch buildOpencodeSpawnConfig failures (bypass / base-URL / runtime-settings-key / keyless / model pass-through)
Tests  7 failed | 27 passed (34)

After the fix (same two files):

Test Files  2 passed (2)
     Tests  34 passed (34)

Full plugin suite + typecheck + lint:

bun run --cwd plugins/plugin-agent-orchestrator test:unit
  Test Files  118 passed (118)
       Tests  1290 passed (1290)
bun run --cwd plugins/plugin-agent-orchestrator typecheck  → exit 0
bunx biome check <4 changed files> → clean

New coverage: model-gateway-env.test.ts now spawns agentType: "opencode" in gateway ON (gateway-routed OPENCODE_CONFIG_CONTENT, no raw key anywhere in the env dump including composite values) and OFF (legacy wiring pinned byte-identical) modes, plus the composite-value sweep; opencode-spawn-config-auto-detect.test.ts covers the gateway branch directly (raw env key, runtime-settings key, custom-base-URL bypass attempt, keyless host, model pass-through, single-var-off) and is now hermetic against host gateway vars.

  • Real-LLM trajectories: N/A — env-assembly/config logic only; no prompt, action, provider-context, or model-behavior change.
  • Screenshots/video/frontend logs: N/A — no UI surface.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f627d5e1-140c-4d1f-a6d4-06c435d8c05f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/gateway-opencode-config-leak

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…ub-agents via OPENCODE_CONFIG_CONTENT

gateway mode (86bc107, #11651) promised a child env dump contains no
raw provider key, but an opencode spawn broke the invariant twice over:
buildOpencodeSpawnConfig embedded the raw cerebras/opencode/cloud key as
provider options.apiKey inside the JSON assigned to
env.OPENCODE_CONFIG_CONTENT, and applyModelGatewayEnv — which runs after
and deletes only the seven named env keys — never touched it. the child
env carried the raw key AND the opencode child pointed its baseURL
straight at api.cerebras.ai / eliza cloud, bypassing the gateway.

- buildOpencodeSpawnConfig checks resolveModelGatewayConfig() first,
  before any credential read (env, runtime settings, or config-env —
  setting() falls back to all three, so env-key deletion alone could
  never fix this). in gateway mode it returns a gateway-pointed
  openai-compatible provider config: nothing raw to leak, and the child
  routes through the gateway instead of bypassing it.
- applyModelGatewayEnv enforces the stated invariant literally: raw
  values captured from the named keys are swept out of every remaining
  env value, so a composite carrier (a JSON blob like
  OPENCODE_CONFIG_CONTENT) that still embeds a raw key is dropped whole.
  fail-closed backstop for future merge steps.

off-mode behavior is byte-identical; a new off-mode test pins the legacy
direct-cerebras wiring. model-gateway-env.test.ts now exercises
agentType opencode — the untested gap that hid this.
@lalalune
lalalune force-pushed the fix/gateway-opencode-config-leak branch from 3f6f49a to b49fb99 Compare July 3, 2026 10:25

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@claude

claude Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants