Hoppa till innehållet

Supabase Function Search Path Mutable: vad det betyder

Supabase

Visa som MarkdownÖppna i ClaudeÖppna i ChatGPTÖppna i Perplexity

Frågan kopieras också. Om chatten öppnas tom, klistra in den.

Kort sagt

Varningen betyder att en funktion saknar fast search_path, så varje okvalificerat namn i den, som admins, slås upp som anroparens session anger. I mitt lokala test returnerade en SECURITY DEFINER-funktion is_admin() true för en icke-admin efter att användaren skapat en temporär tabell som hette admins, och att låsa search_path = public stoppade det inte. Det som fungerade: set search_path = '' med varje tabell skriven som public.admins.

Supabases Security Advisor listar detta som lint 0011, “Function Search Path Mutable”, nivå WARN, med detaljen “Function public.x has a role mutable search_path”. Den flaggar varje funktion utan inställningen, även SECURITY INVOKER-funktioner, så i ett projekt med många hjälpfunktioner blir listan lång: ett open source-projekt åtgärdade 99 av dem i en enda migrering.

Vad betyder “role mutable search_path”?

search_path är listan över scheman som Postgres söker i efter ett namn utan schema framför. En funktion utan egen inställning använder anroparens lista. Supabases lint-sida rekommenderar att sätta den till en tom sträng, vilket tvingar varje referens i funktionen att vara fullt kvalificerad.

För en SECURITY DEFINER-funktion spelar det störst roll: den körs med sin ägares rättigheter, vanligtvis postgres, som kringgår RLS. Om anroparen kan styra vilken admins den läser, styr anroparen en kontroll som körs som postgres.

Går det att utnyttja i mitt test?

På en lokal Postgres 17.10 skapade jag en tabell public.admins med en admin och fyra versioner av samma funktion, select exists (select 1 from admins where user_id = uid), alla SECURITY DEFINER. Sedan loggade jag in som en roll med låga rättigheter som kan köra SQL och har standardrätten att skapa temporära tabeller, och skapade pg_temp.admins med användare A, som inte är admin:

is_admin(A) efter en temp-tabell admins. SECURITY DEFINER-funktion, lokal Postgres 17.10. Ingen search_path: pg_temp.admins → admins → temp → true; search_path = public: pg_temp.admins → admins → temp → true; search_path = '' + public.admins: pg_temp.admins → public.admins → false.
Min återskapning på en lokal Postgres, 24 oktober 2026.
Funktionens inställning Lint-villkor is_admin(A) efter den temporära tabellen
ingen flaggad true
set search_path = public godkänd true
set search_path = '', kroppen använder public.admins godkänd false
set search_path = public, pg_temp godkänd false

Den andra raden är den som överraskade mig. En Supabase-maintainer skrev 2024 att en fast icke-tom sökväg inte innebär någon säkerhetsrisk, och linten accepterar den. Men Postgres söker först i det temporära schemat om inte pg_temp nämns i sökvägen, som dess dokumentation om att skriva SECURITY DEFINER-funktioner varnar för. Så med search_path = public kan en temporär tabell fortfarande skugga ett okvalificerat namn.

Vem kan faktiskt göra detta på Supabase?

Inte en besökare via din app. Data API:t kan varken skapa temporära tabeller eller ändra sessionens search_path, så enbart publishable key tar inte dit. Det krävs en direkt databasanslutning: en andra tjänst med egen inloggning, ett BI- eller rapportverktyg, en konsults skrivskyddade roll, en läckt anslutningssträng. I de flesta små appar är risken låg; i varje projekt där andra personer eller verktyg än du har databasinloggningar, åtgärda definer-funktionerna först.

Hur åtgärdar du det?

Skapa funktionen på nytt med tom sökväg och schemanamn i kroppen:

create or replace function public.is_admin(uid uuid)
returns boolean
language sql stable security definer
set search_path = ''
as $$ select exists (select 1 from public.admins where user_id = uid) $$;

revoke execute on function public.is_admin(uuid) from public, anon;

revoke är lika viktig som sökvägen: en definer-funktion i public kan anropas via Data API:t, så utan den kan vilken gäst som helst fråga /rpc/is_admin om en viss användare är admin. Ge tillbaka den bara till de roller som behöver den, eller håll sådana hjälpfunktioner i ett schema som API:t inte exponerar.

Kör inte bara alter function public.is_admin(uuid) set search_path = ''. Det tystar Advisor och förstör funktionen: i min körning misslyckades nästa anrop med 42P01: relation "admins" does not exist. Operatorer från tillägg behöver också sitt schema, som operator(extensions.<=>) för pgvector.

Så listar du det linten flaggar i public, definer-funktioner först:

select p.proname, p.prosecdef as security_definer
from pg_proc p join pg_namespace n on n.oid = p.pronamespace
where n.nspname = 'public'
  and not exists (select 1 from unnest(coalesce(p.proconfig, '{}')) c
                  where c like 'search_path=%')
order by p.prosecdef desc, p.proname;

Kostar åtgärden något?

Ibland. Varje set-klausul hindrar Postgres från att infoga en enkel SQL-funktion i frågan som anropar den, som rapporterats på GitHub. Jag mätte båda formerna på 200 000 rader med ett index på den filtrerade kolumnen (median av 7 körningar):

SQL-funktion, sedan filtrerad på ägare Utan set set search_path = ''
Filter utanför: visible_items() where owner = ... 0,053 ms, index använt 36,7 ms, full skanning
Filter innanför: items_of(owner) 0,056 ms 0,082 ms

Om en funktion som returnerar en mängd frågas med ett filter utanför, flytta in filtret som parameter innan du låser sökvägen.

Kontrollera ditt projekt

© 2026 Denys Zaichenko. Originalartikel: https://madsalt.tech/sv/notes/supabase-function-search-path-mutable/