MELLEPRISE MELLEPRISE MP Blog
← All articles

lovable security fails because you never wrote a policy

Pastel comic of a rubber stamp hovering over a blank policy sheet with nothing stamped yet

Your lovable security felt solid because users must log in, but the live database stayed public until someone queried it with the anon key.

Preview saves worked. The dashboard listed rows. You published and assumed the login wall protected customer data. It did not. The Supabase client in your browser ships with a public anon key. Without row level security, that key is enough to read and write tables through the REST API. Scrapers do not need your React components.

Never wrote a policy

AI builders excel at auth UI and CRUD screens. They skip the invisible SQL step that locks rows to the signed-in user.

Anyone can list your tables with the anon key

Open browser devtools on your live site. Copy VITE_SUPABASE_URL and the anon key from the bundle. Call the REST endpoint in a new tab or with curl. If rows return without a session, your data was never private.

Inserts work for strangers

Spam rows appear overnight. A table with INSERT grants and no deny policy accepts anonymous writes. Your app only showed “your” notes because the query filtered by user ID in JavaScript. The API does not enforce that filter until policies exist.

RLS enabled but every query fails

You toggled Row Level Security on and the app broke. That is expected until you add allow policies. An empty policy set blocks everything, including legitimate users. The fix is not to turn RLS off. The fix is to write rules.

Service role key in frontend code

Search the repo for service_role. If it appears in client files, your lovable security is worse than none. That key bypasses all policies. Rotate it immediately in Supabase and move admin operations to server routes.

Security work spans policies, keys, and publish settings. Use supabase rls for the SQL path and lovable deploy for the five settings the editor never asked about.

Why Lovable ships lovable security without policies

Lovable generates supabase.from('tasks').select('*') and a login form in the same session. Both look finished in preview. Row Level Security lives in the Supabase SQL editor, not in the component tree the AI edits most often.

Preview feels private because only you use it. The anon key is still public in the bundle, but nobody else is looking. Launch changes the audience. Bots scan new domains within hours.

Supabase auth and RLS are separate switches. Auth creates sessions. RLS decides which rows a session may touch. The AI wires auth because users see it. It skips policies because errors only appear after enablement, and disabling RLS “fixes” the demo quickly.

Tutorials mention “enable RLS” in one sentence. They spend pages on Tailwind and OAuth buttons. You ship with a beautiful shell and an open database.

Merged search intent around supabase security lands here: the gap is not a missing checkbox in Lovable. The gap is Postgres policies you still owe the database.

Fix lovable security in Supabase

Work table by table. User data tables first. Reference tables with only public read data can stay open if you intend that.

  1. Inventory tables with user data. In Supabase Table Editor, list every table holding emails, messages, orders, or profile fields. Skip pure lookup tables only if they contain no private fields.
  2. Enable RLS on each table. Open the table β†’ Settings β†’ enable Row Level Security. Or run alter table public.your_table enable row level security; in the SQL editor.
  3. Add a SELECT policy for owners. Example for a notes table: allow select where auth.uid() = user_id. Use the policy templates in Authentication β†’ Policies if you prefer the UI.
  4. Add INSERT policy. Allow inserts only when auth.uid() = user_id or when the inserted row sets user_id to the current user. Without INSERT policy, saves fail after RLS turns on.
  5. Add UPDATE and DELETE policies. Mirror the owner check for changes and removals. Public read tables need narrower rules.
  6. Test with the anon key outside your app. Use curl or the Supabase REST docs with only the anon key and no session JWT. Confirm foreign rows do not return.
  7. Remove service role from client code. Search the Lovable project for service keys. Delete them from frontend files. Use Edge Functions or server routes for admin tasks.
  8. Republish and regression-test login flows. Save data as a real user on the live site. Confirm another test account cannot read the first user’s rows in the UI or via API.

Policies are code. Version them in migration files when possible so redeploys do not drift.

Checklist before you call lovable security production-ready

  • RLS enabled on every table with private user data
  • SELECT, INSERT, UPDATE, and DELETE policies match your ownership model
  • Anon-key-only API calls cannot read other users’ rows
  • No service role or third-party secret in frontend bundles
  • Live app saves and loads correctly under policies
  • Policy SQL documented or migrated, not only clicked once in the UI

FAQ

Is lovable security enough if users must log in?

No. Login proves identity in the browser. Without server-side row level security, anyone with your public anon key can query tables directly through the Supabase API and bypass your UI filters.

What is the first lovable security fix after publish?

Enable Row Level Security on every table that holds user data, then add SELECT and INSERT policies tied to auth.uid(). Test with the anon key outside your app to confirm rows are blocked.

Does lovable security include API key handling?

Partially. You must treat the Supabase anon key as public and protect data with policies. Service role keys and third-party secrets must never ship in frontend code or public repos.