Security

BundleLLM is designed so that user API keys never touch your servers.

Architecture

Your Site (SDK)  →  LLM Provider API
     ↑                    ↑
  Your code            User's key
  (no keys)          (in their browser)

The SDK runs on your page and calls LLM providers directly from the user’s browser. API keys are stored in the user’s localStorage. they never pass through your server or BundleLLM’s servers.

Key Storage

  • API keys are stored in the browser’s localStorage on your domain
  • Keys are validated against the provider API before storing
  • Users can clear their key at any time by clicking “Disconnect”
  • Clearing browser site data also removes stored keys

API Key Validation

When a user enters an API key, the SDK validates it before connecting:

  • Anthropic: POST /v1/messages with minimal payload
  • OpenRouter: GET /api/v1/auth/key

Invalid keys are rejected immediately. A 429 (rate limited) response is treated as valid. The key works, the user is just rate limited.

OAuth Security

For OpenRouter OAuth, the SDK opens a popup to our OAuth redirect handler:

  1. SDK generates PKCE code verifier + challenge
  2. Popup redirects to OpenRouter’s auth page
  3. User authorizes, OpenRouter redirects back with a code
  4. Our server exchanges the code for an API key via PKCE
  5. The key is returned to the SDK popup via postMessage (origin-restricted)
  6. Our server never stores the key

Protections:

  • PKCE (S256) prevents authorization code interception
  • postMessage origin validation. Key only sent to the opener’s verified origin
  • XSS protection. All values escaped in the callback HTML
  • Rate limiting. 10 OAuth starts per minute per IP
  • State expiry. PKCE state tokens expire after 5 minutes

What the SDK Can Do

  • Show a provider picker for users to connect
  • Store the user’s API key in their browser
  • Send chat messages directly to the provider
  • Display streaming responses and token usage

What the SDK Cannot Do

  • Access API keys from JavaScript on your page (stored in localStorage under a specific key)
  • Send keys to BundleLLM servers (the OAuth server only handles the exchange, never stores keys)
  • Make requests without the user’s explicit connection

Site Owner Obligations

Per the Terms of Service:

  • Do not intercept, log, or transmit users’ API keys
  • Provide a disconnect button
  • Display token usage per message
  • Show which provider the user is connected to

Reporting Issues

If you find a security vulnerability, please email support@dewey-labs.com.