TL;DR
Supabase 30. októbra 2026 prestane na každom existujúcom projekte dávať novým tabuľkám v public automatické granty pre anon, authenticated a service_role. Tabuľky, ktoré už máte, fungujú ďalej. Každá tabuľka vytvorená po tomto dátume odpovie supabase-js aj vášmu secret key chybou 42501 permission denied, kým jej migrácia nedá grant. Prepnutie som reprodukoval lokálne: nové tabuľky, nové views aj staré tabuľky, ktoré migrácia zmaže a vytvorí znova, zlyhajú; existujúce tabuľky, RPC funkcie a inserty do serial fungujú ďalej. Skontrolujte to dvomi SQL dotazmi a jedným grepom nižšie a opravte grantom, RLS a politikou v tej istej migrácii, nikdy nie cez grant all on all tables.
Prevádzkujem bezplatný bezpečnostný checker pre Supabase, ktorý číta granty na každej sprístupnenej tabuľke, a chcel som presne vidieť, čo táto zmena robí, skôr než na ňu ľudia narazia. Postavil som lokálny stack Supabase, dal mu staré defaulty, prepnutie som aplikoval tak, ako ho opisuje Supabase, a poslal som požiadavku na každý druh objektu, ktorý ma napadol. Tento článok je to, čo prišlo späť, a ako skontrolovať vlastný projekt pred 30.
Čo sa mení 30. októbra 2026?
Doteraz dostala každá tabuľka vytvorená v schéme public cez default privileges Postgresu select, insert, update a delete pre anon, authenticated a service_role. Preto bola nová tabuľka dostupná z prehliadača hneď, ako vznikla, chránená RLS alebo nie. Oznámenie o breaking change od Supabase tieto defaulty odoberá v troch krokoch:
| Dátum | Čo sa stane |
|---|---|
| 28. apríla 2026 | Nové projekty môžu pri vytvorení vypnúť “Automatically expose new tables” |
| 30. mája 2026 | Nové správanie sa stane predvoleným pre nové projekty, nasadzuje sa niekoľko týždňov |
| 30. októbra 2026 | Nové správanie sa uplatní na všetky existujúce projekty |
Na vašom projekte je prepnutie dvojica príkazov, tých istých, ktoré Supabase uvádza pre skoršie prijatie:
alter default privileges for role postgres in schema public
revoke select, insert, update, delete on tables from anon, authenticated, service_role;
alter default privileges for role postgres in schema public
revoke usage, select on sequences from anon, authenticated, service_role;
Default privileges platia len pre objekty vytvorené neskôr. Existujúce granty sa nedotknú, preto vaše súčasné tabuľky fungujú ďalej. Čo sa podľa oznámenia nemení: iné schémy (auth, storage, realtime, vaše vlastné), aplikácie komunikujúce s Postgresom priamym pripojením (psql, ORM, server s connection stringom) a samotné RLS. Zmena sa týka Data API: REST, GraphQL a každej klientskej knižnice nad nimi.
Čo sa pokazí a čo funguje ďalej?
Moje prostredie: Supabase CLI 2.109.1, Postgres 17.6, PostgREST 14.14, 26. októbra 2026. V config.toml som nastavil auto_expose_new_tables = true, aby som dostal staré defaulty, vytvoril jednu tabuľku s dvoma riadkami, zapnutým RLS a čítacou politikou a potom spustil dva príkazy vyššie. Potom som vytvoril nové objekty a každý som zavolal lokálnym verejným (anon) kľúčom a secret (service_role) kľúčom, po jednej požiadavke.
| Objekt, vytvorený po prepnutí, ak nie je uvedené inak | Kľúč | Výsledok |
|---|---|---|
| Tabuľka vytvorená pred prepnutím | verejný | HTTP 200, 2 riadky |
Nová tabuľka s RLS a politikou to anon, authenticated |
verejný | HTTP 401, 42501, hint GRANT SELECT ON public.new_orders TO anon; |
| Tá istá nová tabuľka | secret | HTTP 403, 42501, hint … TO service_role; |
Nový view (security_invoker) nad starou tabuľkou |
verejný | HTTP 401, 42501, permission denied for view, hint null |
Kópia vytvorená cez create table … (like old_orders including all) |
verejný | HTTP 401, 42501 |
Stará tabuľka po drop table a opätovnom create table |
verejný | HTTP 401, 42501 |
Nová funkcia public.ping() cez /rest/v1/rpc |
verejný | HTTP 200 |
Nová tabuľka s id serial, pre anon len select, insert |
verejný | insert HTTP 201 |
V tejto tabuľke je päť vecí, ktoré stojí za to vedieť pred prepnutím.
“Existujúce tabuľky si udržia granty” platí, len kým tabuľka existuje. Migrácia, ktorá tabuľku zmaže a vytvorí znova, kópia cez create table … (like …) alebo obnova z dumpu vytvoria novú tabuľku a nová tabuľka nedostane nič. Politika sa vrátila s mojím create policy, granty nie. Čokoľvek vo vašom pipeline, čo tabuľky prestavuje namiesto úpravy, zlyhá pri prvom behu po prepnutí.
Zlyhá aj secret key. service_role obchádza RLS, ale grant stále potrebuje. Takže Edge Function, cron úloha alebo webhook handler, ktorý zapisuje do novej tabuľky, zlyhá s 403, nielen prehliadač. Hint uvádza service_role, podľa čoho to rozoznáte.
Views nedajú hint. Pri tabuľkách PostgREST vráti presný GRANT, ktorý potrebujete. Pri mojom novom view bol hint null a správa znela permission denied for view v_old_orders. AI nástroj, ktorý opravuje 42501 podľa hintu, tu nemá čo skopírovať; grant je grant select on public.v_old_orders to authenticated; a view si má ponechať security_invoker = true, aby sa RLS tabuľky ďalej uplatňovalo.
Funkcie nie sú súčasťou tejto zmeny. Dva príkazy sa týkajú tabuliek a sekvencií. Moja nová funkcia ostala volateľná pre anon, authenticated aj service_role, lebo Postgres dáva execute na každú novú funkciu role PUBLIC a revoke na úrovni schémy ho nedokáže odobrať, ako vysvetľuje príručka Supabase o zabezpečení API. RPC volania fungujú aj po 30. októbri; zároveň to znamená, že nová funkcia security definer je volateľná vaším verejným kľúčom hneď, ako vznikne.
Inserty do serial fungovali aj bez grantu na sekvenciu. Veľa rád hovorí, že serial id po prepnutí potrebuje grant usage on sequence … to authenticated. V mojom behu insert prešiel bez neho: revoke odoberá usage a select na nových sekvenciách, ale update ostáva a update na nextval stačí. Ak odoberiete všetky default privileges na sekvenciách, ako robí úplný revoke v príručke o zabezpečení API, grant na usage potrebujete. Identity stĺpec (generated by default as identity) nepotrebuje nič v oboch prípadoch.
Ešte jedna vec, ktorú revoke necháva: nová tabuľka stále prišla s TRUNCATE, REFERENCES a TRIGGER pre všetky tri roly a na Postgrese 17 defaulty obsahujú aj MAINTAIN. Na TRUNCATE sa nevzťahuje žiadna politika RLS. Písal som o tom v poznámke o 42501.
Kde na to narazíte pred 30. októbrom
Prepnutie na vašom hostovanom projekte je 30., ale tri miesta sa už správajú ako po ňom.
supabase db reset na aktuálnom CLI. CLI v2.102.0 pridalo do config.toml kľúč [api] auto_expose_new_tables. Na 2.109.1 s vynechaným kľúčom mal môj čerstvý stack už nové defaulty: tabuľky dostali len MAINTAIN, REFERENCES, TRIGGER a TRUNCATE, sekvencie len UPDATE. Nastavenie na true vráti staré granty a vypíše api.auto_expose_new_tables is deprecated and will be removed on 2026-10-30. Ak vám teda lokálne tabuľky po resete stále fungujú, skontrolujte najprv tento kľúč. Je to aj najlacnejšie miesto na test: odstráňte ho, urobte reset, spustite aplikáciu.
Preview branche a projekty vytvorené od 30. mája. Prehrávajú vaše migrácie na nových defaultoch. Každá tabuľka, ktorej migrácia nemá grant, je tam už nedostupná. V diskusii na GitHube ľudia s jedným projektom na zákazníka hlásia presne toto: bežiace projekty sú v poriadku, každé nové nasadenie z rovnakých migrácií je rozbité.
Baseline migrácia, ktorá vráti starý default. Komentujúci v tej istej diskusii upozorňuje, že prvá migrácia vytvorená cez supabase db pull môže obsahovať alter default privileges … grant all on tables to anon, authenticated, service_role. Spustil som ten príkaz po prepnutí: ďalšia tabuľka, ktorú som vytvoril, bola znova dostupná, HTTP 200. Lokálne to problém skryje. Na hostovanom projekte potichu zruší zmenu a každá budúca tabuľka je znova otvorená verejnému kľúču, s RLS či bez. Prehľadajte svoje migrácie na alter default privileges a prečítajte si každý nález.
Ako skontrolovať projekt pred 30. októbrom
Štyri kontroly, od najrýchlejšej po najdôkladnejšiu. Prvé dve bežia v SQL Editore hostovaného projektu.
1. Prepol sa už váš projekt?
Toto je dotaz z príručky Supabase o zabezpečení API. Vypíše, čo dostanú nové objekty vytvorené používateľom postgres v public:
select
case d.defaclobjtype
when 'r' then 'tables'
when 'S' then 'sequences'
when 'f' then 'functions'
end as object_type,
a.grantee::regrole as role,
string_agg(a.privilege_type, ', ' order by a.privilege_type) as privileges
from pg_default_acl d
cross join lateral aclexplode(d.defaclacl) a
where d.defaclrole = 'postgres'::regrole
and d.defaclnamespace = 'public'::regnamespace
and a.grantee in ('anon'::regrole, 'authenticated'::regrole, 'service_role'::regrole)
group by 1, 2
order by 1, 2;
Ak riadky tables obsahujú SELECT, INSERT, UPDATE, DELETE, projekt je ešte na starom defaulte a prepne sa 30. Ak ukazujú len MAINTAIN, REFERENCES, TRIGGER, TRUNCATE (alebo žiadne riadky), nové tabuľky sú už zatvorené. Vidíte to aj v Dashboarde v nastaveniach Data API, “Automatically expose new tables”.
2. Ktoré tabuľky majú politiku, ale nemajú grant?
Politika pre rolu, ktorá nemá grant na daný príkaz, sa nikdy nespustí: požiadavka zlyhá pred RLS. Tento dotaz vypíše také dvojice. V mojom laboratóriu našiel novú tabuľku a znova vytvorenú starú a nič iné:
select p.schemaname || '.' || p.tablename as "table", r.role, p.cmd
from pg_policies p
cross join lateral unnest(case when 'public' = any(p.roles) then array['anon', 'authenticated']::name[] else p.roles end) as r(role)
join pg_class c on c.relname = p.tablename
join pg_namespace n on n.oid = c.relnamespace and n.nspname = p.schemaname
where p.schemaname = 'public'
and r.role in ('anon', 'authenticated')
and not has_table_privilege(r.role::text, c.oid,
case p.cmd when 'ALL' then 'SELECT' else p.cmd end)
order by 1, 2, 3;
Spúšťajte ho po každej migrácii, v CI proti čerstvému db reset alebo na stagingu. Na zdravom projekte nevráti nič; po 30. je každý riadok tabuľkou, ktorú vaša aplikácia nedosiahne. Kontroluje granty na úrovni tabuľky, takže tabuľka otvorená len grantmi na stĺpce (grant select (id, name) on …) sa tu objaví, aj keď sú tie stĺpce čitateľné.
3. Ktoré migrácie vytvárajú tabuľku bez grantu?
Databáza ukazuje len tabuľky, ktoré existujú. Migrácia, ktorú ste ešte neaplikovali, je vidieť len vo vašom repozitári. Tento hrubý grep vypíše každé create table v supabase/migrations bez grant … on pre rovnaké meno:
for t in $(grep -hioE 'create table( if not exists)? +[a-z0-9_."]+' supabase/migrations/*.sql | awk '{print $NF}' | sort -u); do
grep -qiF "on $t " supabase/migrations/*.sql || grep -qiF "on table $t " supabase/migrations/*.sql || echo "no grant: $t"
done
Je to porovnávanie textu, nie parsovanie SQL: grant, ktorý uvádza viac tabuliek v jednom príkaze, alebo tabuľka pomenovaná raz bez schémy a inde so schémou, dá falošný nález. Prečítajte si každý riadok, ktorý vypíše. Tabuľky, ku ktorým pristupuje len serverový kód priamym pripojením, grant vôbec nepotrebujú.
4. Prehrajte všetko na nových defaultoch
Odstráňte auto_expose_new_tables z config.toml, spustite supabase db reset a proti tomu spustite aplikáciu alebo jej testy. To je váš projekt po 30., plus čerstvá kópia každej tabuľky, čo je ťažší prípad. Supabase vypisuje dotknuté tabuľky aj v Security Advisor a v Table Editore označuje sprístupnenie cez Data API.
Ako to opraviť bez otvorenia každej tabuľky
Grant, RLS a politiky napíšte do migrácie, ktorá tabuľku vytvára, a každej role dajte len to, čo aplikácia používa:
create table public.invoices (
id bigint generated by default as identity primary key,
user_id uuid not null default auth.uid(),
total numeric not null
);
revoke all on table public.invoices from anon, authenticated, service_role;
grant select, insert on table public.invoices to authenticated;
grant select, insert, update, delete on table public.invoices to service_role;
alter table public.invoices enable row level security;
create policy "Owners read their invoices"
on public.invoices for select
to authenticated
using ((select auth.uid()) = user_id);
create policy "Owners add their invoices"
on public.invoices for insert
to authenticated
with check ((select auth.uid()) = user_id);
Tento blok som spustil na tom istom lokálnom stacku: prihlásený testovací používateľ vložil riadok a prečítal ho späť (HTTP 201, potom 200), verejný kľúč bez session dostal 42501 a kontrola 2 vyššie tabuľku už nevypísala. Úvodné revoke all odstráni TRUNCATE, TRIGGER a REFERENCES, ktoré prichádzajú s novou tabuľkou, a na projekte, ktorý sa ešte neprepol, dáva rovnaký výsledok. Roli anon dávajte grant len na dáta určené pre neprihlásených návštevníkov a service_role len ak serverový kód používa na tejto tabuľke secret key. Ako do seba zapadajú granty a politiky v celej aplikácii, je v mojom bezpečnostnom checkliste pre aplikácie z Lovable.
Čo nerobiť, keď príde prvé 42501:
- Nespúšťajte
grant all on all tables in schema public to anon, authenticated. Vráti starý default naraz na všetky tabuľky, aj na tie, kde sa RLS nikdy nezapol, a tie potom prečíta každý, kto má váš verejný kľúč. Poznámka o 42501 ukazuje, prečo je grant prvý zámok a RLS druhý. - Nepridávajte späť
alter default privileges … grant. Je to rollback celej zmeny. - Nevypínajte RLS kvôli “testovaniu” a nedávajte secret key do frontendu. Secret key obchádza RLS pre každého, kto otvorí váš bundle; rozdiel medzi kľúčmi je v anon key vs service role key.
Ak vaše migrácie píše AI nástroj, pridajte do jeho pokynov jeden riadok: “every new table in public gets explicit grants per role, enable row level security and policies in the same migration; never grant on all tables in schema public”. Hint v chybe ho naučí grant, nikdy nie RLS, ktoré k nemu patrí.
Otázky, ktoré ľudia kladú
Prestanú mi 30. októbra fungovať existujúce tabuľky? Nie. Default privileges platia pre objekty vytvorené neskôr a v mojom behu stará tabuľka po prepnutí odpovedala HTTP 200. Výnimkou je tabuľka, ktorú vaše migrácie zmažú a vytvoria znova.
Musím niečo robiť, ak tabuľky nikdy nevytváram? 30. nie. Skontrolujte to, až keď nejakú pridáte vy, kolega alebo AI nástroj, a skontrolujte každý pipeline, ktorý vytvára projekty alebo branche z vašich migrácií.
Týka sa to Edge Functions? Áno, ak používajú supabase-js so secret key na novej tabuľke: service_role tiež potrebuje grant. Funkcie, ktoré sa pripájajú k Postgresu priamo, to neovplyvní.
Týka sa to RPC funkcií, Storage alebo Auth? V tejto zmene nie. Nové funkcie ostávajú volateľné cez PUBLIC a storage a auth nie sú schéma public.
Môžem prepnúť skôr? Áno. Dva príkazy na začiatku sú prepnutie; spustite ich najprv na stagingu, potom na produkcii. Existujúce tabuľky si granty ponechajú, takže bežiaca aplikácia nič nezbadá a ďalšia nová tabuľka vám hneď povie, či sú vaše migrácie pripravené.
Ako to vidí checker
Checker sa pripája len na čítanie a číta granty na každej tabuľke vo vašich sprístupnených schémach: do ktorých tabuliek môže verejný kľúč zapisovať bez politiky, ktoré tabuľky majú vypnuté RLS a ktoré default privileges ešte dávajú každej novej tabuľke TRUNCATE, REFERENCES alebo TRIGGER. Vypíše aj každú politiku, ktorej rola nemá grant na daný príkaz, teda tabuľky, ktoré nájde kontrola 2, okrem tých s vypnutým RLS alebo so stĺpcovými grantmi. Nevidí súbory migrácií, ktoré ste ešte neaplikovali, takže kontrola 3 vyššie ostáva na vás. Ak si nie ste istí práve RLS, ako testovať Supabase RLS vás ňou prevedie a poznámka o sprístupnených schémach pokrýva schémy iné než public, ktoré táto zmena nechá na pokoji.