Ga naar hoofdinhoud
AIFAIS Logo
AI Privacy & Veiligheid

Supabase RLS Checklist: 7 Attack-paden die AI-Generators Standaard Open Laten

Kort antwoord

Supabase zet Row-Level Security niet automatisch aan op nieuwe tabellen. AI-coding-tools (Lovable, Bolt, Cursor, v0) genereren dit zelden mee. Resultaat: anon-key kan vaak hele tabellen lezen, soms ook schrijven. De checklist hieronder dekt de 7 paden waar we in 5 op 5 NL-audits exploiteerbare lekken vonden.

Waarom dit patroon zo vaak voorkomt

Supabase is een Postgres met REST en Realtime erbovenop. De anon-key wordt publiek in de browser meegestuurd. Of de anon-rol iets mag, hangt af van twee dingen: of RLS aan staat op de tabel, en welke policies daar zijn ingesteld.

Standaard staat RLS UIT op een nieuwe tabel. Een AI-coding-tool die je vraagt 'voeg een leads-tabel toe' draait een ALTER TABLE plus INSERT-INTO, maar zelden ALTER TABLE leads ENABLE ROW LEVEL SECURITY plus CREATE POLICY. We zien dit consistent in 5 op 5 audits.

  • Supabase docs vermelden RLS expliciet maar zetten het niet auto-aan
  • Lovable en Bolt genereren tabellen zonder RLS-blok in 4 van 5 reviews
  • Cursor en v0 vragen er soms naar, maar zonder bewuste prompt = geen RLS
  • Realtime publication is een tweede oppervlak: REST kan dichtstaan terwijl WSS open is
  • PGRST205-foutmelding lekt tabel-namen via Perhaps-you-meant-hints

Attack-pad 1 — anon-SELECT op gevoelige tabellen

De meest voorkomende vondst. Test met een curl-commando vanuit je terminal:

  • curl <project>.supabase.co/rest/v1/leads -H 'apikey: <anon-key>'
  • Verwacht: lege array [] of 401
  • Gevonden in 4 van 5 audits: volledige rijen met PII (email, telefoon, KvK)
  • Fix: ALTER TABLE leads ENABLE ROW LEVEL SECURITY
  • Plus: CREATE POLICY 'eigenaar leest eigen' ON leads FOR SELECT USING (auth.uid() = user_id)

Attack-pad 2 — anon-INSERT op publieke tabellen

Lead-formulieren laten anon-INSERT vaak open zodat het werkt zonder login. Maar zonder validatie kun je nep-leads spammen, of erger:

  • Reviews-tabel met anon-INSERT plus geleakte company-id's = nep-reviews op echte bedrijven
  • Contact-tabel met anon-INSERT = inbox-spam zonder rate-limit
  • Audit-log met anon-INSERT = log-vervuiling die echte aanvallen verbergt
  • Fix: policy WITH CHECK (rate_limit_check() AND honeypot IS NULL)
  • Plus: kolom user_id beperken via auth.uid(), niet client-side

Attack-pad 3 — PATCH op profiles.role of users.is_admin

Bewezen exploit op een productie-app 2026-05-26: anon-key kon profiles.role updaten naar admin. Geen aparte user_roles-tabel, geen JWT-claim-check, alleen een kolom in profiles.

  • curl -X PATCH /rest/v1/profiles?id=eq.<uuid> -H 'apikey: <anon>' -d '{"role":"admin"}'
  • Verwacht: 401 of 204 zonder effect
  • Gevonden: 200 OK plus row geupdate plus directe admin-toegang
  • Fix: aparte user_roles-tabel met service-role-only INSERT
  • Plus: app_metadata.role in JWT-token, niet in app-tabel

Attack-pad 4 — Realtime publication open voor anon

REST kan strak zijn (SELECT geeft []) terwijl WSS publication open staat. Elke INSERT/UPDATE op de tabel komt LIVE bij de aanvaller binnen via een subscribe-channel.

  • Test met @supabase/supabase-js client en .channel().on('postgres_changes')
  • Subscribe op tabel leads, plaats test-lead via UI, kijk of subscribe trigget
  • Bevestigd in 3 van 5 audits: live PII-stream van elke nieuwe inzending
  • Fix: ALTER PUBLICATION supabase_realtime DROP TABLE leads
  • Plus: REALTIME-rechten alleen toekennen aan authenticated-rol, niet anon

Attack-pad 5 — Storage bucket public-read

Storage-buckets staan vaak op public-read voor avatars en publieke assets. Maar dezelfde flag wordt soms gezet op buckets met schadefoto's, paspoort-scans of facturen.

  • curl <project>.supabase.co/storage/v1/object/list/<bucket>
  • Verwacht: 401 of restricted
  • Gevonden: volledige object-listing van 1.500+ PDF-documenten met PII
  • Fix: bucket private maken plus per-object signed URLs (geldig 1 uur)
  • Plus: storage.policies per bucket met auth.uid()-check

Attack-pad 6 — Edge Function zonder rate-limit of auth

Custom Edge Functions (Deno Deploy) vergeten vaak rate-limit en authcheck. Plus: een new Map() als rate-limit-store werkt niet, want elke instance heeft een eigen Map.

  • Test met 30 calls per seconde op /functions/v1/<naam>
  • Verwacht: 429 na 5-10 calls
  • Gevonden: 200 OK op alle 30 plus account_found-leak in response
  • Fix: Upstash Redis voor cross-instance rate-limit
  • Plus: verify_jwt: true in function-config plus consistent foutbericht (geen account_found-leak)

Attack-pad 7 — RPC (SECURITY DEFINER) met anon-EXECUTE

POST /rest/v1/rpc/<naam> met lege body {} test je voor anonieme RPC-execution. cleanup_, verify_, validate_-naamgevingen worden vaak vergeten in lockdown-migraties.

  • curl -X POST /rest/v1/rpc/cleanup_old_sessions -H 'apikey: <anon>' -d '{}'
  • Verwacht: 401 of permission denied
  • Gevonden: 200 OK plus rijen verwijderd door anon-aanroep
  • Fix: REVOKE EXECUTE ON FUNCTION <naam> FROM anon
  • Plus: SECURITY INVOKER ipv SECURITY DEFINER tenzij strikt nodig

Hoe je dit eenmalig checkt in 10 minuten

Onze gratis tool aifais.com/tools/supabase-rls-scan probeert deze 7 paden client-side. Je plakt je Supabase URL plus anon-key, krijgt binnen 30 seconden een lijst met tabellen die anon-readable, anon-writable of via Realtime open zijn.

Geen server-call naar AIFAIS, geen opslag van je keys. De scan draait in je browser. Code is open-source op github.com/AIFAIS/aifais-landing.

Veelgestelde Vragen over Supabase RLS Checklist: 7 Attack-paden die AI-Generators Standaard Open Laten

Probeer onze gratis tools

Vragen over AI voor jouw bedrijf?

Onze experts staan klaar om te helpen. Start met een gratis consult en ontdek wat AI voor jouw bedrijf kan betekenen.

Gratis intake
Binnen 8 weken live
ROI garantie
Supabase RLS Checklist: 7 Attack-paden die AI-Generators Standaard Open Laten | AIFAIS