DEV Community

Cenk KURTOĞLU
Cenk KURTOĞLU

Posted on

October 30, 2026: the Supabase change that will 42501 your next deploy - and the leak that was already there

Fifty-two days from now, Supabase changes what happens to every table you create in an existing project. Not a setting you toggle - a platform default enforcement that lands on all projects at once.

Here is the quiet part nobody warns you about: the migration you already wrote and shipped is the one that breaks, and the leak that matters was probably already there before today.

What actually happens on October 30

Supabase published this as changelog entry #45329 on April 28, 2026. The dates:

Date What changes
2026-05-30 New projects default to opt-in exposure (grant required)
2026-10-30 The same rule is enforced on every existing project

Before the change, a table in public was automatically granted select, insert, update, delete to anon, authenticated, and service_role - reachable through the Data API the moment it existed. After the flip, new tables in public are reachable only if your migration explicitly GRANTs the role.

Existing tables keep their current grants. That is the trap, in two opposite ways:

Trap 1 - your next migration breaks with a 403 that is silent in CI.

create table invoices (
  id uuid primary key default gen_random_uuid(),
  customer_id uuid not null,
  amount_cents integer not null,
  created_at timestamptz default now()
);
Enter fullscreen mode Exit fullscreen mode

Deploy that after October 30 and the first SDK call dies in production with error 42501 permission denied for table invoices - PostgREST short-circuits at the privilege layer before RLS is ever evaluated.

Trap 2 - you are about to "fix" it by opening the whole database.

The first search hit for permission denied for table supabase is the barrel-load answer:

grant all on all tables in schema public to anon, authenticated;
Enter fullscreen mode Exit fullscreen mode

It works. Your table appears in the API immediately. It also hands anonymous visitors select, insert, update, and delete on every table in the database - including and especially the ones you never meant to expose. On a project where RLS is off on even one table, this command is a full database exposure, and it is the exact CVE-2025-48757 class of leak (170 production apps, 303 endpoints, public anon key).

The leak that was already there

While you are thinking about October 30, this is the query that finds your current problem:

select n.nspname as schema,
       c.relname as table,
       c.relrowsecurity as rls_enabled,
       coalesce(string_agg(
         g.grantee || ':' || g.privilege_type, ', '
         order by g.grantee), '(none)') as grants
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
left join information_schema.role_table_grants g
  on g.table_schema = n.nspname
 and g.table_name = c.relname
 and g.grantee in ('anon', 'authenticated')
where n.nspname = 'public'
  and c.relkind in ('r','p')
group by 1,2,3
order by c.relrowsecurity, c.relname;
Enter fullscreen mode Exit fullscreen mode
  • rls_enabled = false with any anon:... grant = every profile in your database returns to a stranger with curl and your anon key. That key ships in your JavaScript bundle.
  • rls_enabled = false with anon:UPDATE on top = the same stranger can also rewrite rows.
  • The row that hurts looks like profiles | false | anon:SELECT, anon:UPDATE.

And the anon key check, one curl:

curl -s "https://YOUR_PROJECT.supabase.co/rest/v1/profiles?select=*" \
  -H "apikey: YOUR_ANON_KEY" | head -20
Enter fullscreen mode Exit fullscreen mode
  • [] = RLS is doing its job.
  • rows = anonymous visitors can read this table.
  • 42501 = the grant did not apply.

What to ship so both traps are impossible

Make grants part of the migration file, next to the table, next to the policies.

create table invoices (
  id uuid primary key default gen_random_uuid(),
  customer_id uuid not null,
  amount_cents integer not null,
  created_at timestamptz default now()
);

grant select on public.invoices to anon;          -- only if genuinely public
grant select, insert, update, delete on public.invoices to authenticated;
grant select, insert, update, delete on public.invoices to service_role;

alter table invoices enable row level security;
create policy "users see own invoices" on invoices
  for select to authenticated using (customer_id = auth.uid());
Enter fullscreen mode Exit fullscreen mode

Three rules:

  1. Grant to authenticated, not anon.
  2. Never grant ... to anon with RLS off.
  3. Never grant all on all tables ... to anon as the fix.

The honest version of the deadline

October 30 does not turn your RLS off. It does not touch existing tables. What it does is stop silently exposing the tables you create from now on - while leaving all the tables you already created exactly as open or closed as they were. The two jobs are separate: grant hygiene going forward, and an audit of what is already reachable today.

Runnable isolation check: https://github.com/cekuu35/supabase-rls-leak-demo

Free PDF checklist: https://cengokurtoglu.gumroad.com/l/nextjs-supabase-10-checks-free


What to do next (Complete 10-Product CTA Ladder)

Need Product Price Time
Quick self-check 7-Surface Supabase Checklist (PDF) Free 2 min
Self-serve audit RLS Audit Kit $29 30 min
Cut bill 50% Supabase Cost Optimization Report $99 24h
Multi-tenant bug Multi-tenant RLS Policy Fix $199 24h
File upload holes File Upload Security $199 24h
Stripe webhook broken? Lovable Stripe Webhook Rescue $399 24-48h
Auth breaks on domain Auth Production Deploy Package $499 24h
Edge functions wide open Edge Function Security Hardening $299 24h
Deploy with confidence Supabase Migration Review $299 24h
All-in-one launch Launch-Ready SaaS Backend Bundle $599 48h
Admin panel missing Admin Panel Scaffold $399 24h
Ongoing monitoring Guard $50/mo $50/mo Recurring

Run the audit query above before October 30. The date is the excuse; the leak was the actual news.

Top comments (0)