How the Caveman Proxy Handles API Credentials: Architecture and Security Explained

The Caveman proxy uses CAVE_API_KEY injected via the x-cave-api-key header to authenticate gateway requests, while leaving provider-specific credentials (OpenAI, Anthropic, Vertex, Bedrock) untouched during forwarding.

The Caveman proxy serves as the secure authentication layer between your applications and upstream LLM providers. Built in Go with a modular provider architecture, it enforces strict separation between gateway authentication (controlled by Caveman Cloud) and provider credentials (controlled by you or your organization). This design prevents credential leakage while supporting both bring-your-own-key (BYOK) and stored key modes.

Gateway Authentication with CAVE_API_KEY

The proxy's primary authentication mechanism relies on a single environment variable: CAVE_API_KEY. This secret confirms that requests originate from an authorized Caveman gateway rather than direct provider access.

Header Injection Pattern

When the proxy receives a request, it automatically appends the x-cave-api-key header containing the gateway secret:


# Environment setup (never commit this)

export CAVE_API_KEY="cave_sk_live_..."

# The proxy injects this header automatically

curl -X POST "http://localhost:8787/w/myapp/openai/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{"model":"gpt-4","messages":[{"role":"user","content":"Hello"}]}'

# Request as seen by upstream provider includes:

# x-cave-api-key: cave_sk_live_...

# Authorization: Bearer sk-openai-...

The skills/caveman-setup/SKILL.md file documents this requirement explicitly: gateway auth uses x-cave-api-key: CAVE_API_KEY and callers authenticate via -H "x-cave-api-key: $CAVE_API_KEY" without manual header management.

Go Implementation Structure

In proxy/providers/vertex/vertex.go and analogous provider files, the forwarding logic checks for the environment variable and injects the header before roundtripping:

// Simplified from proxy/provider adapters
func (a *adapter) RoundTrip(req *http.Request) (*http.Response, error) {
    // Inject gateway authentication
    if caveKey := os.Getenv("CAVE_API_KEY"); caveKey != "" {
        req.Header.Set("x-cave-api-key", caveKey)
    }
    // Provider headers preserved as-is
    return a.base.RoundTrip(req)
}

The proxy/providers/vertex/vertex_test.go file verifies this behavior at lines 168-188, asserting that x-cave-api-key appears in upstream requests without stripping existing headers.

Provider Credential Handling: Two Modes

The proxy supports distinct strategies for managing provider API keys, each with different security properties.

BYOK Mode: Pass-Through Authentication

In bring-your-own-key mode, applications supply their own provider credentials via standard headers (Authorization, x-api-key, etc.). The proxy forwards these unchanged:

  • OpenAI: Authorization: Bearer sk-... passes directly through
  • Anthropic: x-api-key: sk-ant-... preserved intact
  • Vertex: Authorization: Bearer $(gcloud auth print-access-token) forwarded as-is
  • Bedrock: AWS signature headers passed without modification

The proxy/providers/adapter_contract_test.go (lines 152-185) enforces this contract across all providers, ensuring that any header present in the incoming request survives to the upstream call.

Stored Key Mode: Secure Injection

When configured for stored credentials, the proxy retrieves encrypted provider keys from Caveman Cloud and injects them at request time. This mode:

  • Eliminates provider keys from application code
  • Enables centralized key rotation and revocation
  • Maintains audit trails through the gateway

The injection occurs after gateway authentication but before upstream dispatch, using the same header-preserving logic as BYOK mode.

Credential Redaction and Logging Security

Credentials that appear in request payloads undergo systematic redaction before any logging or observability processing. The shared/platform/redact/payload_test.go file (lines 749-751) validates this behavior, confirming that patterns matching API key formats are replaced with [REDACTED] tokens.

This applies to:

  • JSON request/response bodies containing key fields
  • URL query parameters with sensitive values
  • Header values in debug traces

The redaction layer operates at the platform level, ensuring consistent protection across all proxy components.

CLI Integration and Runtime Configuration

The packages/cli/src/index.ts file orchestrates proxy startup and credential propagation:

// CLI startup sequence (simplified from index.ts lines 95-100, 18043-18050)
async function startProxy(): Promise<void> {
  const gatewayUrl = process.env.CAVE_GATEWAY_URL ?? await getPersistedUrl();
  const apiKey = process.env.CAVE_API_KEY ?? await loadFromEnvFile();
  
  const proxy = spawn('caveman-proxy', [], {
    env: {
      ...process.env,
      CAVE_API_KEY: apiKey,
      CAVE_GATEWAY_URL: gatewayUrl,
    }
  });
  
  // Write run-state for other CLI commands
  await writeRunState({ gatewayUrl, pid: proxy.pid });
}

The run-state file maintains active session information, including which gateway secret is in use, enabling subsequent CLI operations to authenticate against the proxy without redundant environment configuration.

Security Boundaries and Threat Model

The proxy architecture establishes clear trust boundaries:

Layer Responsibility Credential Handling
Application Business logic Never sees CAVE_API_KEY; may hold provider keys in BYOK
Proxy Authentication & routing Injects gateway auth; forwards or injects provider auth
Provider Model inference Receives authenticated, authorized requests only

This structure prevents:

  • Credential leakage: Provider keys never logged or returned to callers
  • Gateway forgery: CAVE_API_KEY required for all proxied traffic
  • Cross-tenant access: Gateway keys scoped to specific Caveman workspaces

Summary

  • CAVE_API_KEY environment variable provides gateway authentication, injected as x-cave-api-key header by the proxy
  • Provider credentials pass through unchanged in BYOK mode or get securely injected from encrypted storage
  • Redaction logic in shared/platform/redact ensures credentials never appear in logs
  • CLI startup at packages/cli/src/index.ts propagates credentials to the proxy process via environment variables
  • Contract tests in proxy/providers/*/vertex_test.go, bedrock_test.go, and adapter_contract_test.go verify header preservation across all code paths

Frequently Asked Questions

Where do I set the CAVE_API_KEY for the proxy?

Set CAVE_API_KEY as an environment variable before running caveman start. The CLI automatically propagates this value to the proxy process. You can also define it in a .env file in your project root for local development.

Does the proxy modify my OpenAI or Anthropic API keys?

No. In BYOK mode, all provider headers pass through unchanged. The proxy only adds the x-cave-api-key header for gateway authentication. Provider-specific credentials remain exactly as your application supplies them.

How does Caveman prevent API keys from leaking in logs?

The shared/platform/redact package scans all request and response payloads for credential patterns before logging. Any detected keys are replaced with [REDACTED] tokens. This operates at the platform layer, protecting against accidental exposure in debug output or error traces.

Can I use stored provider keys instead of BYOK?

Yes. When you configure provider keys through Caveman Cloud, the proxy retrieves and injects them automatically. Your application sends requests without provider credentials, and the proxy adds the appropriate authentication before forwarding to the upstream API.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →