Pravidelný RLS audit je jediný způsob, jak nepřehlédnout, že někdo vytvořil tabulku bez ochrany. Tenhle skript ti vypíše seznam všech veřejně přístupných tabulek a kolik mají policies.
Hlavní audit
sql
-- RLS coverage audit pro Supabase (self-hosted i hosted)
SELECT
c.relname AS table_name,
c.relrowsecurity AS rls_enabled,
c.relforcerowsecurity AS rls_forced,
COUNT(p.polname) AS policy_count,
STRING_AGG(p.polname, ', ' ORDER BY p.polname) AS policies
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
LEFT JOIN pg_policy p ON p.polrelid = c.oid
WHERE c.relkind = 'r'
AND n.nspname NOT IN ('pg_catalog', 'information_schema', 'supabase_migrations')
GROUP BY c.relname, c.relrowsecurity, c.relforcerowsecurity
ORDER BY c.relrowsecurity ASC, c.relname;Veřejné views co obchází RLS
Views s SECURITY DEFINER přečte data napřímo — pozor.
sql
SELECT
schemaname,
viewname,
viewowner,
definition
FROM pg_views
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
AND definition ILIKE '%security definer%';Funkce bez search_path (security hole)
sql
SELECT
n.nspname AS schema,
p.proname AS function,
pg_get_function_identity_arguments(p.oid) AS args,
p.prosecdef AS is_definer,
COALESCE(
(SELECT setting FROM unnest(p.proconfig) AS setting WHERE setting LIKE 'search_path=%' LIMIT 1),
'NOT SET'
) AS search_path
FROM pg_proc p
JOIN pg_namespace n ON n.oid = p.pronamespace
WHERE p.prosecdef = true
AND n.nspname NOT IN ('pg_catalog', 'information_schema', 'pg_temp');Pokud search_path u DEFINER funkce není explicitně nastaven, útočník může přepsat
vyhledávací cestu a podvést funkci.