Secure your Lovable app
Lovable ships fast because it makes a lot of decisions for you. Most of those decisions are fine. The Supabase ones are the ones to double-check. Out of the box your database tables are open, your auth is loose, and your storage buckets sometimes don't care who's asking. Here's what to fix before users show up.
- 01
Turn on Row Level Security for every table
This is the big one. Supabase makes RLS available but doesn't enforce it by default, and Lovable usually doesn't turn it on for you. Without RLS, the anon key (which is sitting in your frontend code) lets anyone read every row in every table. "Anyone" includes someone who just opened DevTools.
Read the deep-dive: Broken access controlPaste this into Cursor / Lovable / BoltList every table in my Supabase project. For each one, enable RLS and write a policy that restricts SELECT, INSERT, UPDATE, and DELETE to rows where the user_id column equals auth.uid(). For tables without a user_id, ask me what the ownership rule should be.
- 02
Keep the service role key out of the client
The anon key is meant for the browser. The service role key bypasses RLS and is meant for server code only. If Lovable ever pastes it into a component, or it gets a VITE_ prefix and ships with the build, every guard you set up is gone.
Read the deep-dive: Exposed API keysPaste this into Cursor / Lovable / BoltGrep this project for SUPABASE_SERVICE_ROLE_KEY. Make sure it only appears in server-side code (Edge Functions or API routes), never in src/ files that get shipped to the browser. If it shows up in client code, replace the call with an Edge Function.
- 03
Make sure .env doesn't ship
Vite reads VITE_* variables and bakes them into the client bundle. That's expected for the public ones (URL, anon key). It's not expected for anything else, and it's catastrophic if a real secret accidentally gets the VITE_ prefix.
Read the deep-dive: .env file exposurePaste this into Cursor / Lovable / BoltAudit my .env. Anything prefixed VITE_ will be visible to anyone using my site. Confirm only the Supabase URL and anon key use that prefix. Move all other secrets to server-only env vars and verify .env is in .gitignore.
- 04
Force email confirmation on signup
Supabase auth lets you flip "confirm email" off so testing is faster. Lovable often leaves it off. In production that means anyone can create an account claiming any email. Useful for spammers, terrible for password reset flows.
Read the deep-dive: Unprotected API routesPaste this into Cursor / Lovable / BoltIn my Supabase project settings, confirm that email confirmation is required. If I'm using a custom signup flow, make sure I'm checking the email_confirmed_at field before granting access to protected routes.
- 05
Rate limit the auth endpoints
Without rate limits, anyone can hammer your login endpoint forever, brute-forcing passwords or burning through your auth provider's quota. Supabase has built-in caps but they're generous. Tighten them or add a Cloudflare or Vercel layer on top.
Read the deep-dive: API rate limitingPaste this into Cursor / Lovable / BoltAdd rate limiting to my login and signup endpoints. Cap login attempts to 5 per minute per IP and 20 per minute per email. Return 429 with a clear error when the cap is hit.
- 06
Validate every Edge Function input
Edge Functions get called straight from your frontend, which means the input is fully attacker-controlled. Don't trust the shape, the types, or the values. Use Zod or valibot.
Read the deep-dive: API input validationPaste this into Cursor / Lovable / BoltFor every Supabase Edge Function in this project, add a schema validation step at the top using Zod. Reject the request with a 400 if validation fails. The schema should be strict about types, lengths, and allowed values.
- 07
Force HTTPS on your custom domain
Lovable hosts on an HTTPS subdomain by default. When you connect a custom domain through Vercel or Netlify, make sure the HTTP-to-HTTPS redirect is on and add HSTS. Cookies need the Secure flag too.
Read the deep-dive: HTTPS enforcementPaste this into Cursor / Lovable / BoltConfirm my custom domain redirects HTTP to HTTPS at the host level. Add a Strict-Transport-Security header with max-age=31536000. Make sure any auth cookies are set with Secure and SameSite=Lax.
- 08
Update your privacy policy to name Supabase
If your app uses Supabase, your privacy policy needs to mention it. Same for Stripe, PostHog, any analytics, any email provider. Stripe's onboarding will reject you if your policy doesn't name your subprocessors.
Read the deep-dive: Missing privacy policyPaste this into Cursor / Lovable / BoltGenerate or update my privacy policy. List every third party that processes user data: Supabase (database and auth), and anything else this app uses (Stripe, analytics, email). Cover what data each one sees and where users can request deletion.
Lovable's defaults are tuned for shipping a prototype, not running a production app. The gap between "looks fine on the demo URL" and "safe with real users" is mostly the eight items above. Run Heimdall once your app is past the demo stage and you'll catch the ones you missed.
