Skip to content
unco3Public

About

Local proxy that prevents API key leakage during vibe-coding sessions

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

Repository files navigation

VibeProxy

日本語版はこちら

Vibe-coding sessions leak API keys into LLM context via runtime logs. VibeProxy prevents this by acting as a local proxy that swaps dummy tokens for real API keys.

How It Works

Agent (dummy token) → VibeProxy (localhost) → Real API (real key)
  1. Give your AI agent a dummy token (e.g. vp-local-openai)
  2. VibeProxy intercepts requests, swaps the dummy token for the real API key stored in your OS keychain
  3. The real key never appears in logs, context, or agent memory

Design Principles

Stateless dummy tokens: Tokens like vp-local-openai are deterministic identifiers derived from the service name, not secrets. They simply tell VibeProxy "this request is for the OpenAI service — look up the real key." Since the proxy runs locally on each developer's machine with their own keychain, there is no need for per-person token generation or file-based state (.vibelocal).

Pluggable secret backends: Real API keys are managed via a secret.Provider interface. The default backend uses the OS keychain (macOS Keychain, Linux Secret Service, Windows Credential Manager). Alternative backends (e.g. environment variables, 1Password CLI, AWS Secrets Manager) can be added by implementing a single interface.

Scope & Non-Goals

VibeProxy is intentionally a lightweight, single-purpose local proxy. The following decisions are deliberate and final:

What VibeProxy does:

  • Swap dummy tokens for real API keys on localhost
  • Support any HTTP-header-based auth provider via YAML config (auth_header + auth_scheme)
  • Provide pluggable secret backends (secret.Provider interface)
  • Offer an optional OpenAI-compatible gateway for model-based routing
  • Produce JSON audit logs and provider-compatible error responses

What VibeProxy intentionally does NOT do:

  • Per-person token generation (.vibelocal): Dummy tokens are deterministic markers (vp-local-{service}), not secrets. Since each developer runs their own local proxy with their own keychain, per-user token disambiguation adds complexity without benefit.
  • Plugin/interface-based provider abstraction: The current HeaderProvider + YAML config handles all major LLM providers (OpenAI, Anthropic, Google, Mistral, etc.). Exotic auth schemes (e.g. AWS V4 signing for Bedrock) will be addressed when real demand arises — not speculatively.
  • OpenTelemetry / observability dashboards: A local proxy does not need distributed tracing. slog + JSON audit logs are sufficient. OTel can be bridged from slog if enterprise demand materializes.
  • Framework-based middleware or routing: The standard Go middleware chaining pattern (func(http.Handler) http.Handler) is idiomatic, readable, and requires zero dependencies.

Quick Start

# Clone & build
git clone https://github.com/unco3/vibeproxy.git
cd vibeproxy
go build -o vibe .

# Initialize project config
./vibe init

# Store your real API key in the OS keychain
./vibe auth login openai
./vibe auth login anthropic

# Start the proxy
./vibe start

# Check status
./vibe status

# View audit logs
./vibe logs

# Stop the proxy
./vibe stop

Configuration

vibeproxy.yaml (team-shared, commit to git)

services:
  openai:
    target: https://api.openai.com
    auth_header: Authorization
    auth_scheme: Bearer
    allowed_paths:
      - /v1/chat/completions
      - /v1/embeddings
      - /v1/responses
    rate_limit:
      requests_per_minute: 60

  anthropic:
    target: https://api.anthropic.com
    auth_header: x-api-key
    auth_scheme: ""
    allowed_paths:
      - /v1/messages
    rate_limit:
      requests_per_minute: 60

listen: 127.0.0.1:8080

timeouts:
  read_seconds: 30       # Client request read timeout
  write_seconds: 120     # Response write timeout (long for LLM streaming)
  upstream_seconds: 90   # Upstream API response header timeout

cors:
  enabled: false
  allowed_origins:       # Wildcard "*" is not allowed
    - http://localhost:3000

# Optional: secret_backend: env  (default: keychain)

# Optional: OpenAI-compatible gateway
# gateway:
#   enabled: true
#   paths:
#     - /v1/chat/completions
#     - /v1/embeddings
#   models:
#     gpt-: openai
#     claude-: anthropic

.env (agent reference, gitignored)

Generated by vibe init. Point your agent's environment here:

VIBEPROXY_URL=http://127.0.0.1:8080
OPENAI_API_KEY=vp-local-openai
ANTHROPIC_API_KEY=vp-local-anthropic

Request Flow

Request
  → Localhost validation
  → CORS (if enabled)
  → Audit (start time, agent identity)
  → Body size limit (10 MB)
  → [Gateway path] → Token validation → Rate limit → Translate → Upstream API
  → [Proxy path]   → Token extraction (Authorization / x-api-key)
                    → Route resolution (vp-local-{service} → service name)
                    → Path whitelist check (with path normalization)
                    → Rate limit check
                    → Secret lookup (on demand, not stored in context)
                    → httputil.ReverseProxy → Upstream API
  → Response → Audit log

Architecture

Feature Detail
Token Swap Extracts dummy token from Authorization or x-api-key headers, resolves the real key from the secret provider, and forwards the request
Localhost Only Binds to 127.0.0.1 — refuses non-localhost addresses
Path Whitelist Only configured API paths are proxied; all others return 403. Paths are normalized (path.Clean) to prevent traversal attacks
Rate Limiting In-memory sliding window counter per service (resets on restart)
Timeout Control Configurable read/write/upstream timeouts to handle slow or hanging APIs
CORS Optional CORS support for browser-based agent UIs (disabled by default). Wildcard * origin is rejected at startup
Error Formatting Provider-compatible error responses (OpenAI/Anthropic SDK format)
Gateway Optional OpenAI-compatible universal API — route by model prefix to any provider. Requires vp-local-* token, enforces rate limits and audit logging
Body Limit Request bodies are limited to 10 MB to prevent memory exhaustion from oversized payloads
Audit Log JSON Lines at ~/.vibeproxy/audit.log — timestamps, methods, paths, status codes, durations (no secrets)
Daemon Mode Background process via self-re-exec with PID file at ~/.vibeproxy/vibeproxy.pid

CLI Reference

Command Description
vibe init Generate vibeproxy.yaml, .env and update .gitignore
vibe auth login <provider> Store an API key via the secret provider
vibe start Start the proxy as a background daemon
vibe start --foreground Start the proxy in the foreground
vibe stop Stop the running proxy
vibe status Show whether the proxy is running
vibe logs [-n 20] Show recent audit log entries
vibe service install Register as OS service (macOS launchd; auto-start on boot)
vibe service uninstall Remove from OS services

Security Model

  • Real API keys are stored via pluggable secret providers (default: OS keychain)
  • Keys are loaded into memory on demand, resolved inline at the point of use, and never stored in request context, disk, or logs
  • Dummy tokens (vp-local-*) are static identifiers, not secrets — safe to appear in logs, .env files, and LLM context
  • Service names in tokens are validated (lowercase alphanumeric + hyphen only) to prevent log injection
  • The proxy binds exclusively to localhost — no network exposure
  • Path whitelisting with path.Clean normalization prevents access to unintended API endpoints and path traversal
  • Request body size is limited to 10 MB to prevent memory exhaustion
  • The gateway requires a valid vp-local-* dummy token, enforces rate limits, and writes audit logs — same security guarantees as the proxy path
  • CORS wildcard origin (*) is rejected at startup to prevent browser-based attacks against localhost
  • PID file creation uses exclusive file locking (O_EXCL) to prevent race conditions

Requirements

  • Go 1.21+
  • macOS / Linux / Windows (via go-keyring)

About

Local proxy that prevents API key leakage during vibe-coding sessions

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages