General

Preventing LLM API Key Leaks

How to avoid leaking OpenAI, Anthropic, and other AI API keys

Last updated 2026-01-15

The LLM Key Leak Epidemic

LLM API keys are among the most frequently leaked secrets today. OpenAI, Anthropic, Google, and Cohere keys are found in public GitHub repositories, client-side JavaScript, mobile app binaries, and browser network requests daily. The financial impact is significant -- leaked keys are immediately exploited by attackers who run massive inference workloads, generating bills of thousands of dollars within hours.

How Keys Get Leaked

1. Hardcoded in Frontend Code

// BAD: Visible in browser source and network requests
const openai = new OpenAI({
  apiKey: 'sk-proj-abc123...',
  dangerouslyAllowBrowser: true,  // The name says it all
});

The dangerouslyAllowBrowser flag exists for prototyping only. Any key used with this flag will be extracted within minutes of deployment.

2. Committed to Git

# These are in your git history forever, even after deletion
$ git log --all -p -- .env
$ git log --all -p -- '*.ts' | grep "sk-"

Even if you delete the file containing the key, it remains in git history. Secret scanning tools run by attackers specifically target git history.

3. Embedded in Mobile Apps

// BAD: Extractable from the APK
class AIService {
    private val apiKey = "sk-ant-api03-..."

    suspend fun complete(prompt: String): String {
        // Direct API call with embedded key
    }
}

4. Exposed in Environment Variables

# .env file committed to repo
OPENAI_API_KEY=sk-proj-abc123
ANTHROPIC_API_KEY=sk-ant-api03-xyz789

# Or logged to console
console.log('Config:', process.env);  // Leaks all env vars

5. Client-Side API Calls

Even without hardcoding the key, making direct LLM API calls from the client exposes the key in network requests:

// BAD: Key visible in browser DevTools Network tab
fetch('https://api.openai.com/v1/chat/completions', {
  headers: { 'Authorization': 'Bearer sk-proj-abc123...' },
  // ...
});

Secure Architecture

Use a Server-Side Proxy

The correct architecture routes all LLM requests through your backend:

Client App --> Your Backend/Edge Function --> LLM API
              (key stored here)
// Supabase Edge Function as an LLM proxy
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';

Deno.serve(async (req: Request) => {
  // 1. Authenticate the user
  const supabase = createClient(
    Deno.env.get('SUPABASE_URL')!,
    Deno.env.get('SUPABASE_ANON_KEY')!,
    { global: { headers: { Authorization: req.headers.get('Authorization')! } } }
  );
  const { data: { user } } = await supabase.auth.getUser();
  if (!user) {
    return new Response('Unauthorized', { status: 401 });
  }

  // 2. Check rate limits and credits
  const adminClient = createClient(
    Deno.env.get('SUPABASE_URL')!,
    Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
  );
  const { data: profile } = await adminClient
    .from('profiles')
    .select('credits')
    .eq('id', user.id)
    .single();

  if (!profile || profile.credits < 1) {
    return new Response('Insufficient credits', { status: 403 });
  }

  // 3. Make the LLM call server-side
  const { prompt } = await req.json();
  const llmResponse = await fetch('https://api.anthropic.com/v1/messages', {
    method: 'POST',
    headers: {
      'x-api-key': Deno.env.get('ANTHROPIC_API_KEY')!,  // Server-side only
      'Content-Type': 'application/json',
      'anthropic-version': '2023-06-01',
    },
    body: JSON.stringify({
      model: 'claude-sonnet-4-20250514',
      max_tokens: 1024,
      messages: [{ role: 'user', content: prompt }],
    }),
  });

  // 4. Deduct credit
  await adminClient
    .from('profiles')
    .update({ credits: profile.credits - 1 })
    .eq('id', user.id);

  return new Response(llmResponse.body, {
    headers: { 'Content-Type': 'application/json' },
  });
});

Set Spending Limits

Every LLM provider offers spending limits or usage caps. Configure them:

  • OpenAI: Set monthly spending limits in the billing dashboard
  • Anthropic: Configure spend limits in the console
  • Google AI: Set quota limits per project

Even with perfect security, set limits as a safety net.

Rotate Keys Regularly

Treat LLM API keys like passwords:

  • Rotate keys on a regular schedule (monthly or quarterly)
  • Rotate immediately if there is any suspicion of compromise
  • Use separate keys for development and production
  • Use separate keys for different services or environments

Use Scoped Keys When Available

Some providers offer scoped or restricted keys:

  • Use project-scoped keys instead of organization-wide keys
  • Restrict key permissions to only the models and endpoints needed
  • Use separate keys for different applications

Git Protection

Pre-commit Hooks

Use tools like gitleaks or detect-secrets to catch keys before they are committed:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

.gitignore

Ensure environment files are ignored:

# .gitignore
.env
.env.local
.env.production
*.key
*.pem

GitHub Secret Scanning

Enable GitHub's secret scanning and push protection on your repositories. GitHub partners with OpenAI, Google, and other providers to automatically revoke leaked keys.

What To Do If a Key Is Leaked

  1. Revoke the key immediately -- Do not wait. Generate a new key first, update your servers, then revoke the old one.
  2. Check usage logs -- Most providers show API usage. Check for unauthorized calls.
  3. Audit git history -- If the key was committed, it is in the history forever. Consider using git-filter-repo or BFG Repo-Cleaner to remove it.
  4. Rotate all related credentials -- If one key was leaked, assume other secrets in the same environment may also be compromised.

Automated Detection

AuditYour.app scans your applications for exposed LLM API keys in frontend code, mobile binaries, and public configurations. Catch leaks before attackers do.

Scan your app for this vulnerability

AuditYourApp automatically detects security misconfigurations in Supabase and Firebase projects. Get actionable remediation in minutes.

Run Free Scan