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
Identify exposed keys in your codebase
Search your entire Lovable project for hardcoded API keys. Check both TypeScript files and any configuration files.
# 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.
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.
// In DevTools Console, search for keys in the JS bundle
// Click Sources tab > Search (Ctrl+Shift+F)
// Search for: sk-proj sk-live apiKey secretRotate 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.
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.
// 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" }
})
})Set secrets in Supabase dashboard
Add your new API keys as secrets in the Supabase dashboard under Edge Functions > Secrets.
# Or via CLI
supabase secrets set OPENAI_API_KEY=sk-proj-your-new-key
supabase secrets set STRIPE_SECRET_KEY=sk-live-your-new-keyUpdate frontend code to call Edge Functions
Replace direct API calls with calls to your new Edge Functions.
// 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 }
})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