Keep your API keys out of the browser.
Anything your frontend ships, anyone can read. Here is the short version of how to protect your keys when building with Lovable, Bolt, Cursor or v0.
1. Know which keys are allowed to be public
Some keys are designed to be public: the Supabase anon / sb_publishable_ key, Stripe pk_live_ keys, and referrer-restricted Google Maps keys. Others must never reach the browser: OpenAI sk-, Anthropic sk-ant-, Stripe sk_live_, Supabase service_role / sb_secret_, AWS access keys.
2. Put secret calls behind a server
Call paid APIs from a server route, Supabase Edge Function or serverless function. The browser calls your endpoint; your endpoint holds the key in an environment variable. In Next.js, never prefix a secret with NEXT_PUBLIC_; in Vite, never with VITE_ — those prefixes are bundled into public JS.
3. Turn on Row Level Security
A public anon key is only safe if every Supabase table has RLS enabled with sensible policies. Without RLS, the anon key can read and write your tables.
4. Never commit .env
Add .env* to .gitignore, and make sure your host doesn't serve /.env or /.git/. Removing a key in a later commit doesn't remove it from git history.
5. Limit the blast radius
Set spend limits and usage alerts on AI providers, use restricted/scoped keys, and restrict Google keys by HTTP referrer and API.
6. If a key leaked: rotate first, investigate second
Revoke and replace the key in the provider dashboard immediately, deploy the new key server-side only, then check usage logs and billing for abuse. Deleting the file is not enough — assume it was already copied. Real examples: a stolen Gemini key, a spend limit that capped the damage, and all leaked-key stories.