Step-by-Step Guide
7 steps

How to Fix API Key Exposure in Lovable Apps

Lovable apps frequently ship with API keys hardcoded in frontend code. When your OpenAI, Stripe, or other secret keys are in the browser bundle, anyone can extract and abuse them. This guide shows you exactly how to find, remove, and properly secure exposed keys.

Find security issues automatically before attackers do.

Follow These Steps

1

Identify exposed keys in your codebase

Search your entire Lovable project for hardcoded API keys. Check both TypeScript files and any configuration files.

Code Example
# Search for common secret patterns
grep -rn "sk-proj-\|sk-live\|sk_live\|OPENAI\|STRIPE.*SECRET\|ANTHROPIC" src/
grep -rn "apiKey.*=.*[\x27\x22]" src/ --include="*.ts" --include="*.tsx"

Supabase anon keys (eyJhbGci...) and Firebase API keys (AIzaSy...) are safe in frontend code. Only flag secret keys like sk-proj-, sk-live-, or database passwords.

2

Check your browser network tab

Open your deployed app, go to DevTools > Network tab, and look for requests that include API keys in headers or URLs. This confirms which keys are exposed.

Code Example
// In DevTools Console, search for keys in the JS bundle
// Click Sources tab > Search (Ctrl+Shift+F)
// Search for: sk-proj  sk-live  apiKey  secret
3

Rotate all compromised keys immediately

Any key that was ever in frontend code must be considered compromised. Go to each provider dashboard and generate new keys before fixing the code.

Do this BEFORE fixing the code. The old keys are already exposed and could be in use by attackers right now.

4

Create Supabase Edge Functions for API calls

Move API calls that require secret keys to Supabase Edge Functions. These run server-side where secrets are safe.

Code Example
// supabase/functions/generate-text/index.ts
import { serve } from "https://deno.land/std@0.168.0/http/server.ts"
import { createClient } from "https://esm.sh/@supabase/supabase-js@2"

serve(async (req) => {
  // Verify the user is authenticated
  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 })

  // Use secret key server-side
  const apiKey = Deno.env.get("OPENAI_API_KEY")!
  const { prompt } = await req.json()
  
  const response = await fetch("https://api.openai.com/v1/chat/completions", {
    method: "POST",
    headers: { "Authorization": `Bearer ${apiKey}`, "Content-Type": "application/json" },
    body: JSON.stringify({ model: "gpt-4o", messages: [{ role: "user", content: prompt }] })
  })
  
  return new Response(JSON.stringify(await response.json()), {
    headers: { "Content-Type": "application/json" }
  })
})
5

Set secrets in Supabase dashboard

Add your new API keys as secrets in the Supabase dashboard under Edge Functions > Secrets.

Code Example
# Or via CLI
supabase secrets set OPENAI_API_KEY=sk-proj-your-new-key
supabase secrets set STRIPE_SECRET_KEY=sk-live-your-new-key
6

Update frontend code to call Edge Functions

Replace direct API calls with calls to your new Edge Functions.

Code Example
// Before (INSECURE - key in frontend)
const response = await fetch("https://api.openai.com/v1/chat/completions", {
  headers: { "Authorization": "Bearer sk-proj-EXPOSED-KEY" }
})

// After (SECURE - key in Edge Function)
const { data, error } = await supabase.functions.invoke("generate-text", {
  body: { prompt: userInput }
})
7

Verify the fix with a security scan

Deploy your changes and run a VAS scan to confirm no API keys are exposed in the frontend bundle.

Also check the browser DevTools Sources tab to verify no secret keys appear in the JavaScript bundle.

What You'll Achieve

All secret API keys are removed from frontend code, rotated to new values, and securely stored in Supabase Edge Function secrets. Your Lovable app now makes API calls through server-side functions where secrets are never exposed to the browser.

Common Mistakes to Avoid

Mistake

Removing the key from code but not rotating it

Fix

If a key was ever in frontend code or git history, it is compromised. Always generate a new key before fixing the code.

Mistake

Moving keys to .env but still bundling them into frontend code

Fix

In frameworks like Vite and Next.js, only environment variables with specific prefixes (VITE_, NEXT_PUBLIC_) are bundled into frontend code. Ensure secret keys do NOT have these prefixes.

Mistake

Confusing Supabase anon key with service_role key

Fix

The anon key is safe for frontend use. The service_role key bypasses RLS and must never be in frontend code. Check your Supabase dashboard to identify which key you are using.

Frequently Asked Questions

Is my Supabase anon key a secret?

No. The Supabase anon key is designed for frontend use. It only has the permissions you define through Row Level Security policies. It is safe to include in your client-side code.

How do I know if my API key has been stolen?

Check your API provider dashboard for unusual usage spikes, unexpected charges, or requests from unknown IP addresses. Most providers show usage logs and alerts.

Can I use environment variables in Lovable?

Lovable generates frontend code that runs in the browser. Environment variables in the browser bundle are visible to everyone. You need server-side code (Supabase Edge Functions) to keep secrets safe.

Ready to Secure Your App?

VAS automatically scans your deployed app for the security issues covered in this guide. Get actionable results in minutes.

Start Security Scan