Lovable · Bolt · Supabase

My users can see data from other accounts.

Your AI-built app works, but every logged-in user sees everyone's data. Here is why it happens, how to confirm it, and how to fix it properly.

What you're seeing

You log in with a second account and the dashboard shows the first account's projects, notes, orders or customers. Or a tester tells you they can see records they never created. Sometimes it is subtler: a list is empty for new users but a search or a direct link reveals someone else's row.

This is not a display bug. The database is answering every question it is asked, for anyone who asks. Nothing in your app is telling it who is allowed to see what.

Why it happens

Supabase exposes your Postgres tables directly to the browser through its API. The key your app ships with (the anon key) is meant to be public. What protects the data is Row Level Security (RLS): rules on each table that say which rows a given user may read, insert, update or delete.

AI builders very often create tables without RLS turned on, or turn it on and add a permissive policy such as using (true) to make an error go away. Both mean the same thing: every row is visible to every user, and if the policy has no role restriction, even to visitors who are not logged in. The app looks finished because the AI tested it with one account.

The opposite failure is just as common: RLS is on and the policy is right, but the user_id column is never filled in when a row is created, so the policy matches nothing and the table looks empty to everyone. If that is what you are seeing, step 2 of the fix below is the part you need.

How to check

  1. Create a second test account and log in with it in a private browser window. If you see anything the first account created, you have the problem.
  2. Open the Supabase dashboard, go to Table Editor and look at each table. A red "RLS disabled" label means the table is open to everyone.
  3. Go to Database → Policies. A table with RLS enabled but no policies blocks everyone; a policy whose expression is just true allows everyone.
  4. Run the two queries below in the SQL Editor. The first lists which tables have RLS on; the second lists every policy and its rule.
-- Which public tables have Row Level Security enabled?
select tablename, rowsecurity
from pg_tables
where schemaname = 'public'
order by tablename;

-- Every policy, with the rule it applies
select tablename, policyname, cmd, roles, qual, with_check
from pg_policies
where schemaname = 'public'
order by tablename, policyname;

Anything with rowsecurity = false, or a qual of true, is what you are looking for.

How to fix it

For the common case, where each row belongs to one user through a user_id column that references auth.users, these policies do the whole job. Replace projects with your table name and run them in the SQL Editor, one table at a time.

-- 1. Turn RLS on. Nothing is protected until this runs.
alter table public.projects enable row level security;

-- 2. Make sure new rows always belong to the person creating them.
alter table public.projects
  alter column user_id set default auth.uid(),
  alter column user_id set not null;

-- 3. Owners can read their own rows.
create policy "Users read their own projects"
  on public.projects for select
  to authenticated
  using (auth.uid() = user_id);

-- 4. Owners can create rows only for themselves.
create policy "Users insert their own projects"
  on public.projects for insert
  to authenticated
  with check (auth.uid() = user_id);

-- 5. Owners can change and delete only their own rows.
create policy "Users update their own projects"
  on public.projects for update
  to authenticated
  using (auth.uid() = user_id)
  with check (auth.uid() = user_id);

create policy "Users delete their own projects"
  on public.projects for delete
  to authenticated
  using (auth.uid() = user_id);

Step 2 will fail if the table already has rows with an empty user_id. Decide who those rows belong to (or delete them if they are test data) before setting the column to not null.

One more consequence of step 2: rows created from the SQL Editor, a server using the service-role key, or a seed script have no logged-in user, so auth.uid() is empty there. In those cases pass user_id explicitly, or the insert fails on the not-null rule.

Then remove any policy whose rule is true, and repeat the second test-account check. Each user should now see only their own rows, and a logged-out visitor should see nothing.

Three things that quietly undo this fix: a service-role key used in the browser (it bypasses RLS entirely and must only live on a server), database views (they run with their owner's privileges and skip the table's RLS unless created with security_invoker = on) or functions marked security definer that read the table on the user's behalf, and asking the AI builder to "fix the error" after RLS is on, which often makes it disable RLS again. Check the policies after every AI change that touches the database.

When to get a human

The policies above assume one owner per row. The moment data is shared, teams, organisations, clients with several users, an admin who sees everything, the rule becomes "is this user a member of the group that owns this row", and that needs a membership table and policies that join to it. Getting it wrong either leaks data again or locks legitimate users out.

It is also worth a human when existing production data has no owner, when the app relies on views or functions you did not write, or when you cannot tell which of the AI's tables are still in use. That is a few hours for someone who has done it before, and it is exactly the kind of one-off problem a Patch exists for.

Last reviewed 2026-09-17. Written by HumanPatch for people who built a product with AI and got stuck.

FAQ

Questions about this fix

Is it a problem that my Supabase anon key is visible in the browser?

No. The anon key is designed to be public. Row Level Security is what protects the data. The service-role key is the one that must never reach the browser, because it bypasses RLS.

My app stopped showing any data after I enabled RLS. Did I break it?

No, that is RLS working. A table with RLS on and no policies denies everything. Add the select policy for the owner and the data comes back, now only for its owner.

Can I just ask Lovable or Bolt to fix it?

You can, and sometimes it does. Often, though, it removes the error by disabling RLS or adding a policy that allows everyone, which is the original problem. After any AI change, run the policy query above and do the second-account test.

How long does this fix take?

For a single owner column, under an hour for someone who knows Supabase, most of it testing. For shared data (teams, organisations, admins) it is a small data-model change first, then the policies.

Still stuck?

Tell us what’s blocking your product and find the right human to finish the job.