Lovable app security checklist: 10 checks before you publish
Lovable builds a React front end that talks directly to a Supabase backend (Lovable Cloud or your own Supabase project). That architecture is fine, but it means the browser holds a public key to your database, and your Row Level Security policies decide what anyone can read or change. Work through this list before you share your app.
Scan your live app free Passive, no signup, never touches your database.
1. Run Lovable's own security scan, then read the findings
Lovable's docs describe a Quick scan that runs automatically on publish (database access rules, dependency audit, unauthenticated MCP servers) and a Deep scan that reviews application code, including access control, abusable endpoints and leaked secrets. Use both. The docs themselves say the scans don't guarantee complete security.
2. Review every RLS policy, not just whether one exists
In Lovable: More → Cloud → Database → RLS policies (per Lovable's docs). A policy with USING (true) counts as 'RLS enabled' but lets every row through. The researcher who reported CVE-2025-48757 criticised an earlier Lovable scanner for checking only that policies exist, not that they're correct. For user-owned data, policies should compare auth.uid() to the owner column.
alter table public.notes enable row level security;
create policy "Owners can read" on public.notes
for select to authenticated
using ((select auth.uid()) = user_id);
create policy "Owners can insert" on public.notes
for insert to authenticated
with check ((select auth.uid()) = user_id);
create policy "Owners can update" on public.notes
for update to authenticated
using ((select auth.uid()) = user_id)
with check ((select auth.uid()) = user_id);
create policy "Owners can delete" on public.notes
for delete to authenticated
using ((select auth.uid()) = user_id);3. Test as a second user and as nobody
Sign up a second account and try to open the first account's records (change IDs in the URL, watch the Network tab). Then log out and repeat. Lovable's security best-practices page recommends verifying that 'users cannot access other users' private data' before going live.
4. Keep the service role key out of the front end
Lovable's docs note that server-side code using the service role bypasses RLS and must check permissions itself. That key belongs only in edge function secrets. If it ever appears in your published JavaScript, rotate it immediately.
5. Put third-party API keys in edge functions
OpenAI, Stripe, Resend and similar keys must be stored as secrets for your edge/server functions, never pasted into React code. Anything in the browser bundle is public.
6. Make edge functions check who is calling
An edge function that sends email, calls an AI API or touches payments must verify the caller's JWT and permissions, or it becomes a free, abusable endpoint.
7. Check storage buckets
Public buckets serve every file to anyone with the URL. Keep uploads like invoices or ID documents in private buckets with storage policies.
8. Turn on leaked-password protection and email confirmation
These are auth settings in your Supabase/Lovable Cloud project. Lovable's Quick scan flags leaked-password protection being off.
9. Add security headers on your custom domain
If you host the app yourself (e.g. Vercel or Netlify), add CSP, HSTS, X-Frame-Options and nosniff with the snippets in our header guides. On builder-managed hosting, check what headers you can configure.
10. Scan the published URL
Run Unspill against your live URL to catch leaked keys, public source maps, an exposed .env and missing headers. It reads only public files and never queries your database.
Fix guides for these issues
- Verify Supabase Row Level Security: Your Supabase anon key is public by design, so Row Level Security is the only thing protecting your tables. Run these SQL checks to find tables with RLS off or policies that let anyone read everything.
- Supabase service_role key exposed: A Supabase service_role (or sb_secret_) key in front-end code gives anyone full read/write access to your database, bypassing Row Level Security. Here is how to rotate it and fix the leak.
- AI API key exposed: An OpenAI, Anthropic, Groq, OpenRouter or xAI key in your front-end bundle lets anyone run up your bill. Revoke it and proxy AI calls through a server function with rate limits.
- Stripe secret key exposed: A Stripe sk_live_ or sk_test_ key in your JavaScript lets anyone create charges, issue refunds and read your customers. Roll the key in the Stripe Dashboard and move payments server-side.
- Public source maps: Production .map files let anyone rebuild your original front-end code, comments and internal routes. Disable them in Vite or Next.js, or upload them privately to your error tracker.
- Content-Security-Policy: A Content-Security-Policy limits which scripts can run on your site, reducing the damage of XSS. Copy-paste CSP examples for Vercel, Netlify and Next.js apps using Supabase.
- Clickjacking protection: If any site can load your app in an iframe, attackers can trick users into clicking buttons they can't see. Add X-Frame-Options: DENY or CSP frame-ancestors 'none'.
FAQ
Is it safe that my Supabase anon key is visible in my Lovable app?
Yes, the anon (publishable) key is designed to be public. It is only safe if every table exposed through the API has correct Row Level Security policies.
Lovable's security scan passed. Am I done?
Not necessarily. Lovable's own docs say the scans help but don't guarantee complete security. Also test access with a second account and logged out, and review policy conditions, not just their existence.
Where do I put my OpenAI or Stripe secret key in Lovable?
In the secrets for your edge (server) functions. Call the third-party API from the edge function, never from React code.
Sources
- Lovable docs: Security overview
- Lovable docs: Security best practices
- Supabase docs: Row Level Security
- CVE-2025-48757 write-up (Matt Palmer)
Last checked against these sources on 2026-10-19. Platforms change; when in doubt, the official docs win.