← BlogLovable3 min readUpdated 2026-08-03

Lovable: your admin page is hidden, not protected

If the only thing stopping a stranger reaching /admin is that you did not link to it, you do not have access control.


Ask Lovable for an admin dashboard and you get one. Ask it to make sure only admins can open it, and you get a check in the UI — a conditional that hides the link, or redirects if a role does not match. That is a front-door sign, not a lock.

Why UI checks are not access control

Every check written in your React components runs in the visitor's browser, on code they control. They can navigate straight to the route, edit the JavaScript, or simply call the same Supabase query the page would have called. The data lives behind the database, so the database must be the thing enforcing who reads it.

Check it yourself, two minutes

Visit your own app as a stranger

  1. 1Open a private/incognito window so you are signed out.
  2. 2Type your admin URL directly: yourapp.com/admin, then /dashboard, /settings, /users.
  3. 3Note what happens — a login screen is correct, a rendered page is not.
  4. 4Now sign in as an ordinary, non-admin user and repeat.
  5. 5Finally, take any URL containing an ID (/orders/1041) and change the number. If you see someone else's record, that is a separate and serious bug.

The last step matters more than the first. Most Lovable apps do gate the admin page somehow; far fewer check that user A cannot request user B's row by changing a number in the address bar.

Fix it

Paste this into Lovable
Make my access control real instead of cosmetic.

1. List every route that is meant to be restricted, and show me exactly
   where each one is enforced. Any route whose only protection is a
   conditional render or a client-side redirect is not protected — mark it.
2. Move enforcement into the database with Row Level Security, so the rule
   holds no matter who calls the query:
   - admin-only tables: a policy checking the caller's role, not a flag
     sent from the browser
   - per-user rows: USING ((select auth.uid()) = user_id)
3. Store roles in a table the user cannot write to. If a role lives in
   user metadata the client can edit, an ordinary user can promote
   themselves — fix that first.
4. For every route that loads a record by id, add an ownership check so
   requesting another id returns nothing rather than someone else's data.

Show me a list of routes, what enforces each one now, and what an
anonymous visitor and a normal signed-in user get for each.

This is one check out of 40+

Paste your site address and we run the whole list from the outside — leaked keys, open databases, unprotected pages — then hand you one prompt that fixes what we find. Free, about 30 seconds, no signup.

Check my site — free