Credential proxy

By default, orka keeps provider API keys out of the sandbox. --no-proxy restores direct forwarding: ANTHROPIC_API_KEY, OPENAI_API_KEY, and OPEN_ROUTER_KEY are passed from the host environment into the container, where the agent (and anything it runs) can read them.

orka -- "fix the build"             # keys concealed behind the proxy
orka --no-proxy -- "fix the build"  # keys forwarded directly

The proxy is skipped automatically, with keys forwarded directly, when neither ANTHROPIC_API_KEY nor OPENAI_API_KEY is set on the host, or under --engine container (a note is printed).

How it works

Before the container starts, orka launches a reverse proxy inside its own process, bound to an ephemeral port. The proxy is the only holder of the real keys. The container receives, for each provider whose key is set on the host:

ProviderContainer env
AnthropicANTHROPIC_API_KEY=<token>, ANTHROPIC_BASE_URL=http://orka-proxy.internal:<port>/anthropic
OpenAIOPENAI_API_KEY=<token>, OPENAI_BASE_URL=http://orka-proxy.internal:<port>/openai/v1

ORKA_PROXY is also set to the space-separated names of the proxied keys. The container startup banner reports each key as proxied, set, or unset; set means the raw credential is readable by the agent and is printed in yellow.

<token> is 32 random bytes, generated per run. The agent’s SDK sends it back in its usual credential header; the proxy rejects any request without it, swaps in the real key on match, and forwards the request over TLS to the pinned provider host. Responses, including SSE streams, are relayed as they arrive. The proxy exits with orka.

Harness routing

Only claude reaches the proxy through the base-URL env vars above. Pi and codex ignore them, so orka routes each by mounting a merged copy of its config file read-only over the harness’s own path inside the container. The host file is never modified, and everything else in it is preserved in the merged copy.

HarnessRoute
ClaudeANTHROPIC_BASE_URL
Piproviders.<name>.baseUrl in ~/.pi/agent/models.json
Codexopenai_base_url in ~/.codex/config.toml

Pi’s model catalog pins each SDK’s base URL explicitly, so only a provider-level baseUrl overrides it. Its models.json is read as JSON5 (trailing commas and comments allowed), approximating the repair pass pi applies to it; the merged overlay is written as strict JSON.

Codex resolves the built-in openai provider’s endpoint from openai_base_url alone, and entries under model_providers cannot override built-in provider ids. The merged config.toml keeps the user’s comments and formatting.

When the route cannot be established — the user’s config already points a proxied provider elsewhere (routing the token to an endpoint that expects the real key), codex’s model_provider selects a provider the proxy does not cover, or the file cannot be parsed — orka warns and forwards the keys directly for that run.

Reaching the proxy

The container reaches the proxy through orka-proxy.internal, added with --add-host=orka-proxy.internal:host-gateway (Docker 20.10+, Podman 4.1+). The bubblewrap backend shares the host network namespace and uses 127.0.0.1 directly.

Exposure

  • The container-to-proxy hop is plain HTTP on a host-local interface; the proxy-to-provider hop is TLS.
  • Under Docker, the proxy binds only to the bridge gateway address, so nothing off the host can reach it. Under Podman and bubblewrap fallback cases it binds all interfaces and prints a notice; the per-run token is then the access control. The token grants use of this proxy’s pinned upstreams for the lifetime of the run — never the keys themselves.
  • The agent can still spend your API quota through the proxy while it runs. Concealment stops exfiltration of the keys, not use of them.

Limitations

  • OPEN_ROUTER_KEY has no base-URL env override, so it cannot be routed through the proxy. While the proxy is active it is withheld from the container entirely and OpenRouter models are unavailable; pass --no-proxy to use them.
  • The mounted overlay is read-only, so a harness write to its own config file fails inside the container while the proxy is active: ~/.pi/agent/models.json for pi, ~/.codex/config.toml for codex.
  • Provider credentials stored inside mounted agent config directories (~/.pi, ~/.claude, ~/.codex), such as OAuth tokens or auth.json keys, are outside the proxy’s reach. Shadow those files if they must stay hidden — see shadow files.