{"id":49511,"date":"2026-10-29T20:47:25","date_gmt":"2026-10-29T13:47:25","guid":{"rendered":"https:\/\/sunbytes.io\/?p=49511"},"modified":"2026-10-29T20:49:47","modified_gmt":"2026-10-29T13:49:47","slug":"supabase-rls-ai-built-apps","status":"publish","type":"post","link":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/","title":{"rendered":"Supabase RLS: hoe vibe-coded apps data kunnen lekken en hoe u dat controleert"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In een klassieke webapp staat een server tussen de browser en de database, en die server bepaalt wie wat ziet. Als een Supabase-app de database rechtstreeks vanuit de browser bevraagt via de Supabase Data API, staat die server er niet tussen. Dan moet de database zelf beslissen. Supabase RLS (Row Level Security) is die beslissing. Ontbreekt RLS of is een policy te ruim, dan kunnen rijen van andere klanten leesbaar worden met de publieke key, terwijl de app gewoon blijft werken.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Deze gids hoort bij onze reeks over <a href=\"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/ai-coding-in-productie\/\" target=\"_blank\" rel=\"noopener\">AI-gebouwde producten veilig in productie<\/a>. U leest vijf RLS-gaten die klantdata kunnen blootleggen, een controle zonder SQL, een veilige volgorde om ze te herstellen en wat een gat betekent onder de AVG (GDPR).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">TL;DR<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Supabase RLS is de set regels in een Supabase-database die bepaalt welke rijen elke gebruiker mag lezen of wijzigen. Als de browser de database rechtstreeks bevraagt, kan iedereen met de publieke key een tabel zonder RLS lezen en wijzigen, en kan een te ruime RLS-policy rijen tonen aan gebruikers die ze niet mogen zien. Elke bezoeker kan de publieke key zien.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Vijf RLS-gaten<\/strong> uit deze gids kunnen klantdata blootleggen in een AI-gebouwde Supabase-app: RLS uitgeschakeld, elke ingelogde gebruiker die alle rijen leest, ruime policies voor wijzigen, een klant-ID uit de browser, en achterdeuren via service_role, views of functies.<\/li>\n\n\n\n<li><strong>Een RLS-controle op founderniveau<\/strong> vraagt geen SQL: drie controles en zes vragen aan uw developer. Een RLS-gat geeft geen foutmelding: een eigenaarsaccount dat zijn eigen data test, ziet een werkende app.<\/li>\n\n\n\n<li><strong>Een veilig RLS-herstel<\/strong> gaat tabel voor tabel in een stagingkopie en is klaar wanneer een tweede testaccount niets ziet wat het niet mag zien.<\/li>\n\n\n\n<li><strong>Een RLS-gat in persoonsgegevens<\/strong> raakt aan passende beveiliging onder AVG artikel 32. Leidt het gat tot een inbreuk in verband met persoonsgegevens, dan kan artikel 33 de verwerkingsverantwoordelijke verplichten de Autoriteit Persoonsgegevens zonder onredelijke vertraging en zo mogelijk binnen 72 uur na kennisname te informeren, tenzij de inbreuk waarschijnlijk geen risico oplevert voor de betrokkenen.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Wat Supabase RLS doet, in gewone taal<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Supabase RLS (Row Level Security) is een PostgreSQL-functie die regels aan een tabel koppelt en elke query op die tabel filtert voordat er een rij de database verlaat. Elke regel heet een RLS-policy. De <a href=\"https:\/\/supabase.com\/docs\/guides\/database\/postgres\/row-level-security\" target=\"_blank\" rel=\"noopener\">Supabase-gids over Row Level Security<\/a> beschrijft een policy als een automatisch toegevoegde WHERE-clausule: wat de browser ook vraagt, de database geeft alleen de rijen terug die de policy toestaat.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Elk verzoek aan de Data API draait onder een van drie databaserollen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>anon<\/strong> is elke bezoeker die niet is ingelogd.<\/li>\n\n\n\n<li><strong>authenticated<\/strong> is elke ingelogde gebruiker. Dat betekent niet &#8220;de eigenaar van deze rij&#8221;, alleen &#8220;iemand met een account&#8221;.<\/li>\n\n\n\n<li><strong>service_role<\/strong> is een serverrol met volledige rechten die RLS volledig overslaat. Die key mag dus nooit in de browser terechtkomen.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">De publieke key in uw frontendcode (de anon key, of publishable key in nieuwere projecten) is bedoeld om openbaar te zijn. De <a href=\"https:\/\/supabase.com\/docs\/guides\/getting-started\/api-keys\" target=\"_blank\" rel=\"noopener\">Supabase-documentatie over API-keys<\/a> noemt de publishable key &#8220;safe to expose online&#8221; en wijst RLS aan als de bescherming van de data erachter. De key is dus maar zo veilig als uw policies. Echte geheimen zijn een apart risico: zie <a href=\"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/gelekte-api-keys-in-ai-producten\/\" target=\"_blank\" rel=\"noopener\">gelekte API-keys in AI-producten<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-request-flow-1-1024x576.webp\" alt=\"Hoe een Supabase-verzoek een tabel bereikt: verzoeken van anon en authenticated gaan door de RLS-policy, service_role slaat die over.\" class=\"wp-image-49533\" srcset=\"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-request-flow-1-1024x576.webp 1024w, https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-request-flow-1-300x169.webp 300w, https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-request-flow-1-768x432.webp 768w, https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-request-flow-1-178x100.webp 178w, https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-request-flow-1-1536x864.webp 1536w, https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-request-flow-1.webp 1600w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\"><em>Hoe een Supabase-verzoek een tabel bereikt: verzoeken van anon en authenticated gaan door de RLS-policy, service_role slaat die over.<\/em><\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Waarom AI-gebouwde apps op Supabase RLS-gaten kunnen krijgen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Drie mechanismen kunnen RLS-gaten veroorzaken in een AI-gebouwde Supabase-app, en geen van de drie verschijnt als fout op het scherm.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Het eerste is hoe een tabel ontstaat. Supabase zet RLS aan voor tabellen die in het dashboard worden aangemaakt, volgens de <a href=\"https:\/\/supabase.com\/blog\/supabase-security-2025-retro\" target=\"_blank\" rel=\"noopener\">Supabase security retro over 2025<\/a>. Een tabel die via een SQL-migratie ontstaat, ook een migratie die een AI-codeertool schreef, krijgt alleen RLS als de migratie dat vastlegt. De functie werkt gewoon, dus een ontbrekende policy valt bij normaal gebruik niet op.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Het tweede is RLS die half is ingericht. Zodra RLS aanstaat, bereikt er geen data de browser tot er policies zijn, en blijven schermen leeg. Twee snelkoppelingen laten ze weer werken, RLS uitzetten of een policy toevoegen die alles toestaat, en beide zetten de tabel weer open. Volgens de <a href=\"https:\/\/supabase.com\/changelog\/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically\" target=\"_blank\" rel=\"noopener\">Supabase-changelog<\/a> hebben nieuwe tabellen in het public-schema vanaf 30 oktober 2026 in alle projecten een expliciete grant nodig voordat de Data API ze kan bereiken. Een grant zonder RLS zet de tabel weer open.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Het derde is de test zelf. Een test met \u00e9\u00e9n eigenaarsaccount toont alleen de eigen rijen van dat account, dus een ontbrekende eigendomscontrole komt daarin niet naar boven. Waarom een geslaagde test dit kan missen, leest u in onze gids over <strong>AI-applicaties testen<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Heeft een AI-tool na de lancering tabellen in uw project aangemaakt? Behandel ze dan als ongecontroleerd tot iemand de policies heeft bevestigd.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Vijf RLS-gaten die klantdata kunnen blootleggen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Deze gids deelt RLS-blootstelling in AI-gebouwde Supabase-apps in vijf gaten in. Vier daarvan blokkeren de lancering wanneer de tabel persoonsgegevens of klantdata bevat; die beoordeling is een aanbeveling van deze gids, geen categorie van Supabase of de AVG.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th><strong>Gat<\/strong><\/th><th><strong>Wat een andere gebruiker kan doen<\/strong><\/th><th><strong>Gevolg voor uw bedrijf<\/strong><\/th><th><strong>Blokkeert de lancering?<\/strong><\/th><\/tr><\/thead><tbody><tr><td>1. RLS uitgeschakeld op een tabel<\/td><td>Elke rij lezen en wijzigen zonder in te loggen, als de anon-rol grants op de tabel heeft<\/td><td>Volledige tabel open; toegang tot persoonsgegevens kan een datalek onder de AVG zijn<\/td><td>Ja, bij persoonsgegevens of klantdata<\/td><\/tr><tr><td>2. Elke ingelogde gebruiker leest alle rijen<\/td><td>Een account aanmaken en de rijen van alle klanten lezen<\/td><td>Open voor iedereen die een account kan aanmaken, als registratie openstaat<\/td><td>Ja, bij persoonsgegevens of klantdata<\/td><\/tr><tr><td>3. Strakke policy voor lezen, ruime policy voor wijzigen<\/td><td>Rijen van iemand anders wijzigen of aanmaken<\/td><td>Records gewijzigd of aangemaakt door de verkeerde gebruiker<\/td><td>Herstellen voor lancering als gebruikers gedeelde records bewerken<\/td><\/tr><tr><td>4. Klant- of team-ID uit de browser<\/td><td>Het ID aanpassen en de omgeving van een andere klant openen<\/td><td>Een B2B-klant kan data van een andere klant zien<\/td><td>Ja, bij persoonsgegevens of klantdata<\/td><\/tr><tr><td>5. Achterdeuren: service_role, views, functies<\/td><td>Rijen bereiken via een pad dat RLS overslaat<\/td><td>Blootstelling die de policies van de tabel zelf niet tonen<\/td><td>Ja, bij persoonsgegevens of klantdata<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Tabel 1. Vijf Supabase RLS-gaten, het gevolg voor uw bedrijf en of ze de lancering blokkeren<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">RLS uitgeschakeld op een tabel<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Een tabel met uitgeschakelde RLS staat open voor iedereen met uw publieke key, zolang de Data API de tabel kan bereiken. De Supabase project linter beoordeelt dit als een <a href=\"https:\/\/supabase.github.io\/splinter\/0013_rls_disabled_in_public\" target=\"_blank\" rel=\"noopener\">bevinding op ERROR-niveau, &#8220;RLS Disabled in Public&#8221;<\/a>, en noemt het &#8220;a critically unsafe configuration&#8221;. Staan er namen, e-mailadressen of facturen in de tabel, dan kan onbevoegde toegang tot die rijen gelden als een datalek onder de AVG.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Policies waarmee elke ingelogde gebruiker alle rijen leest<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Een policy die alleen controleert of iemand is ingelogd, geeft elke accounthouder alle rijen. Policies zoals &#8220;alles toestaan&#8221;, &#8220;elke authenticated gebruiker toestaan&#8221; of &#8220;elk niet-leeg user-ID toestaan&#8221; laten een functie voor elk account werken en komen dus door een functionele test. Bij openbare registratie gelden ze voor iedereen die een account wil aanmaken. Deze regel mag nooit de enige controle op een klanttabel zijn:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>using ( auth.uid() is not null )<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Waar u op let: een policy die controleert dat er een gebruiker is, niet dat de rij van die gebruiker is.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Een strakke policy voor lezen, een ruime voor wijzigen<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Supabase RLS-policies worden per bewerking geschreven: select (lezen), insert (toevoegen), update (wijzigen) en delete (verwijderen). PostgreSQL weigert een bewerking zonder policy, dus een ontbrekende delete-policy maakt een knop onbruikbaar maar legt geen data bloot. De blootstelling ontstaat wanneer een eigendomscontrole op lezen samengaat met een schrijfpolicy die alles toestaat of het user-ID van iemand anders accepteert. Herstel dit voor de lancering als gebruikers gedeelde records bewerken, zoals orders of facturen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Klant- of team-ID uit de browser<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In een multi-tenant SaaS-product kan een policy die een bedrijfs- of team-ID uit de browser vertrouwt, de data van de ene klant blootleggen aan de andere. Accepteert de policy elk ID dat het verzoek meestuurt, dan kan een gebruiker die dat ID aanpast de rijen van een andere klant bereiken. Een veilige policy zoekt het lidmaatschap op in een tabel aan de serverkant die gekoppeld is aan auth.uid(), het ID van de ingelogde gebruiker. Lekken tussen klantomgevingen horen bij de bredere categorie <strong>broken access control<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Achterdeuren rond RLS: service_role, views en databasefuncties<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Drie paden slaan RLS over, ook als elke tabelpolicy klopt. De service_role-key omzeilt alle policies en hoort alleen op een server. Views die door de postgres-rol zijn aangemaakt, omzeilen RLS standaard, volgens de Supabase-gids over RLS, die de optie security_invoker aanbeveelt op PostgreSQL 15 of later. Functies met security definer draaien met de rechten van hun maker, en de <a href=\"https:\/\/supabase.com\/docs\/guides\/api\/securing-your-api\" target=\"_blank\" rel=\"noopener\">Supabase-gids over het beveiligen van uw API<\/a> meldt dat RLS niet geldt voor functies. Storage-buckets hebben hun eigen toegangspolicies, en Firebase-apps gebruiken een ander mechanisme dat dezelfde controle nodig heeft: <strong>Firebase security rules<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Supabase Auth en RLS: waar inloggen stopt en datatoegang begint<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Supabase Auth beantwoordt de vraag &#8220;wie is deze gebruiker?&#8221;; RLS beantwoordt de vraag &#8220;welke rijen mag deze gebruiker aanraken?&#8221;. Een werkende login zegt dus niets over datatoegang: Auth geeft het token uit dat de browser met zijn verzoeken meestuurt, en RLS leest dat token om te bepalen wat het verzoek mag zien.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">De brug is auth.uid(), een hulpfunctie die binnen een policy het ID van de ingelogde gebruiker teruggeeft. Een goede policy vergelijkt daarom de eigenaarskolom van de rij met auth.uid() of controleert een lidmaatschapstabel. Rollen zoals admin of viewer kunnen uit custom claims komen die via auth.jwt() worden gelezen, op voorwaarde dat de server ze instelt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Drie instellingen in Supabase Auth bepalen wat &#8220;authenticated&#8221; waard is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Openbare registratie<\/strong> maakt iedereen die zich aanmeldt tot authenticated gebruiker.<\/li>\n\n\n\n<li><strong>Confirm Email uitgeschakeld<\/strong> laat gebruikers inloggen zonder hun e-mailadres te bevestigen.<\/li>\n\n\n\n<li><strong>Anonymous sign-ins<\/strong> geven bezoekers de authenticated-rol zonder account (zie de <a href=\"https:\/\/supabase.com\/docs\/guides\/auth\/auth-anonymous\" target=\"_blank\" rel=\"noopener\">Supabase-gids over anonymous sign-ins<\/a>).<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Staat registratie open voor iedereen? Lees &#8220;authenticated&#8221; dan als &#8220;iedereen&#8221; wanneer u een policy beoordeelt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Zo controleert u uw Supabase RLS zonder SQL te lezen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">U controleert Supabase RLS zonder SQL met drie controles en zes vragen aan uw developer: de controles laten zien waar RLS ontbreekt, de vragen of de bestaande policies eigendom controleren.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Tabeloverzicht.<\/strong> Noteer in de Table Editor elke tabel met <strong>RLS disabled<\/strong> in de werkbalk of een <strong>Unrestricted<\/strong>-badge in de tabellijst, en markeer welke persoonsgegevens of klantdata bevatten.<\/li>\n\n\n\n<li><strong>Bevindingen in de Security Advisor.<\/strong> Open <strong>Advisors \u2192 Security Advisor<\/strong> (<code>\/dashboard\/project\/&lt;ref&gt;\/advisors\/security<\/code>) en lees elke error en warning. Volgens de security retro over 2025 stuurt Supabase eigenaren van de organisatie ook een wekelijkse e-mail met deze bevindingen.<\/li>\n\n\n\n<li><strong>Lijst met policies.<\/strong> Vraag uw developer om elke RLS-policy per tabel, met per policy \u00e9\u00e9n zin over wie de rijen mag lezen en wie ze mag wijzigen.<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-tabellijst-1-1024x576.webp\" alt=\"Voorbeeld van controle 1: een tabellijst met \u00e9\u00e9n tabel gemarkeerd als RLS disabled en Unrestricted (fictief project, geen echte data).\" class=\"wp-image-49536\" srcset=\"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-tabellijst-1-1024x576.webp 1024w, https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-tabellijst-1-300x169.webp 300w, https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-tabellijst-1-768x432.webp 768w, https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-tabellijst-1-1536x864.webp 1536w, https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-tabellijst-1-178x100.webp 178w, https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/sunbytes-supabase-rls-ai-apps-tabellijst-1.webp 1600w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\"><em>Voorbeeld van controle 1: een tabellijst met \u00e9\u00e9n tabel gemarkeerd als RLS disabled en Unrestricted (fictief project, geen echte data).<\/em><\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Zes vragen om door te sturen naar uw developer:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Welke tabellen bevatten persoonsgegevens of klantdata?<\/li>\n\n\n\n<li>Staat RLS aan op elk van die tabellen?<\/li>\n\n\n\n<li>Controleert elke policy eigendom of teamlidmaatschap, of alleen dat de gebruiker is ingelogd?<\/li>\n\n\n\n<li>Komt het klant- of team-ID in een policy uit een lidmaatschapstabel aan de serverkant of uit de browser?<\/li>\n\n\n\n<li>Wordt de service_role-key of een secret key ergens buiten servercode gebruikt?<\/li>\n\n\n\n<li>Welke views of databasefuncties kunnen deze tabellen lezen, en respecteren ze RLS?<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Een controle met twee accounts toetst de antwoorden in de praktijk: log in als twee testgebruikers en probeer elkaars data te zien, te wijzigen of te verwijderen. De volledige teststappen staan in onze gids over <strong>AI-applicaties testen<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Faalt een tabel met persoonsgegevens op controle 1, of controleert een policy op die tabel alleen &#8220;ingelogd&#8221; terwijl registratie openstaat? Pauzeer dan nieuwe registraties en de onboarding van klanten tot het is hersteld.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Krijgt u als antwoord &#8220;elke ingelogde gebruiker&#8221; of &#8220;dat zoeken we nog uit&#8221;? Beschouw de policies dan als niet gereviewd. Een onafhankelijke reviewer kan uw Supabase-policies samen met de code die ze aanroept lezen en helpen vaststellen, in begrijpelijke taal, welke tabellen openstaan.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/sunbytes.io\/nl\/tech-service\/ai-built-product\/\" target=\"_blank\" rel=\"noopener\"><strong>Vraag een AI-built product review aan \u2192<\/strong><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">RLS herstellen zonder de app te breken<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Supabase RLS veilig herstellen betekent tabel voor tabel werken in een stagingkopie, omdat RLS aanzetten voordat er policies zijn de schermen in productie leegmaakt. Deze volgorde begint bij tabellen die zonder inloggen openstaan en scherpt daarna de policies aan:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Zet RLS aan op elke tabel die de Data API kan bereiken<\/strong>, eerst die met persoonsgegevens en klantdata.<\/li>\n\n\n\n<li><strong>Voeg \u00e9\u00e9n policy per bewerking toe<\/strong>, gekoppeld aan auth.uid() of een lidmaatschapstabel.<\/li>\n\n\n\n<li><strong>Verplaats controles op de klantomgeving naar de serverkant<\/strong>, zodat geen policy een ID uit de browser vertrouwt.<\/li>\n\n\n\n<li><strong>Haal de service_role-key uit de clientcode en roteer hem<\/strong> (zie <a href=\"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/gelekte-api-keys-in-ai-producten\/\" target=\"_blank\" rel=\"noopener\">gelekte API-keys in AI-producten<\/a>).<\/li>\n\n\n\n<li><strong>Beveilig views en functies<\/strong>: security_invoker op views en een review van elke security definer-functie.<\/li>\n\n\n\n<li><strong>Indexeer de kolommen waarop uw policies filteren<\/strong>, zoals user_id of tenant_id.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Voer na elke tabel de controle met twee accounts uit, zodat een leeg scherm een probleem van \u00e9\u00e9n tabel blijft. Een degelijke policy voor een tabel van \u00e9\u00e9n gebruiker is kort:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>using ( (select auth.uid()) = user_id )<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Waar u op let: de eigenaarskolom van de rij vergeleken met het ID van de ingelogde gebruiker.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pas policies ter plekke aan als elke rij haar eigenaar al opslaat in een kolom user_id of tenant_id. Hebben rijen geen eigenaar, dan vraagt het herstel een wijziging in het datamodel, die u het best plant voordat er meer klantdata binnenkomt. Supabase publiceert <a href=\"https:\/\/supabase.com\/docs\/guides\/ai-tools\/ai-prompts\/database-rls-policies\" target=\"_blank\" rel=\"noopener\">AI-prompttemplates voor RLS-policies<\/a>, maar een prompt controleert zijn eigen uitkomst niet. Een mens voert daarna nog steeds de controle met twee accounts uit.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Het herstel is klaar wanneer elke tabel die de Data API kan bereiken RLS aan heeft, elke policy haar eigendoms- of lidmaatschapscontrole benoemt en een tweede account niets ziet wat het niet mag zien.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wat een RLS-gat betekent voor uw bedrijf<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Een RLS-gat in een tabel met persoonsgegevens heeft juridische en technische gevolgen. Artikel 32 van de <a href=\"https:\/\/eur-lex.europa.eu\/legal-content\/NL\/TXT\/?uri=CELEX:32016R0679\" target=\"_blank\" rel=\"noopener\">AVG<\/a> verplicht verwerkingsverantwoordelijken en verwerkers tot technische en organisatorische maatregelen die passen bij het risico. Een inbreuk in verband met persoonsgegevens gaat onder de AVG verder dan data die is gelezen: het gaat om een inbreuk op de beveiliging die leidt tot vernietiging, verlies, wijziging of ongeoorloofde verstrekking van of toegang tot persoonsgegevens, per ongeluk of onrechtmatig. Moet zo&#8217;n inbreuk worden gemeld en is uw bedrijf de verwerkingsverantwoordelijke, dan verplicht artikel 33 tot melding bij de toezichthouder, in Nederland de <a href=\"https:\/\/autoriteitpersoonsgegevens.nl\/nl\/onderwerpen\/beveiliging\/meldplicht-datalekken\" target=\"_blank\" rel=\"noopener\">Autoriteit Persoonsgegevens<\/a>. Dat gebeurt zonder onredelijke vertraging en zo mogelijk binnen 72 uur nadat de verwerkingsverantwoordelijke kennis heeft genomen van de inbreuk, tenzij de inbreuk waarschijnlijk geen risico oplevert voor de betrokkenen. Een verwerker meldt een inbreuk zonder onredelijke vertraging aan de verwerkingsverantwoordelijke. Of uw bedrijf verwerkingsverantwoordelijke of verwerker is, hangt af van hoe het de gegevens verwerkt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wat er in de praktijk volgt na een lek, leest u in ons artikel over <strong>beveiligingsrisico&#8217;s van vibe coding<\/strong>. Een tweede gevolg kan via sales komen: een securityvragenlijst van een zakelijke klant kan vragen hoe klantdata gescheiden is, en &#8220;wij gebruiken Supabase&#8221; is geen volledig antwoord. Supabase levert RLS, maar de policies zijn van u.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Een eigen controle kan een redelijke eerste stap zijn als elke gebruiker alleen zijn eigen data ziet en u nog geen B2B-klanten hebt. Overweeg een onafhankelijke review als het product multi-tenant is, persoonsgegevens van EU-inwoners opslaat of een B2B-securityreview tegemoet ziet. Een <strong>review van AI-gebouwde SaaS<\/strong> zet RLS naast andere controles waar een koper naar kan vragen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Zo reviewt Sunbytes producten die op Supabase draaien<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">RLS-gaten zitten niet alleen in tabelpolicies: een view, een databasefunctie of een serverroute die de hoofdsleutel gebruikt, kan dezelfde rijen blootleggen. Daarom controleren wij Supabase-policies als onderdeel van een bredere review.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Elke RLS-policy wordt gelezen naast de edge functions, serverroutes en views die dezelfde tabel raken, zodat een functie die dezelfde rijen met de service_role-key leest samen met de policy wordt gecontroleerd. U krijgt bevindingen met bewijs, een geprioriteerd actieplan en een technische overdracht waarmee uw developer of AI-codeertool aan de slag kan, in begrijpelijke taal in plaats van een scannerexport.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sunbytes brengt meer dan 15 jaar ervaring en ruim 300 opgeleverde softwareprojecten mee naar die review. De scope hangt af van uw stack en data. Vraag daarom een <a href=\"https:\/\/sunbytes.io\/nl\/tech-service\/ai-built-product\/\" target=\"_blank\" rel=\"noopener\">AI-built product review<\/a> aan of <strong><a href=\"https:\/\/sunbytes.io\/nl\/contact\/\" data-type=\"link\" data-id=\"https:\/\/sunbytes.io\/nl\/contact\/\" target=\"_blank\" rel=\"noreferrer noopener\">neem contact met ons op<\/a><\/strong> voor advies per situatie.<\/p>\n\n\n<section class=\"faq-section faq-section--sidebar alignfull wp-block-sb-block-faq-section is-layout-flow wp-block-sb-block-faq-section-is-layout-flow\">\n            <div class=\"faq-section__intro faq-section__intro--sidebar\">\n                            <div class=\"faq-section__intro-text\">\n                                            <h2 class=\"faq-section__title\">FAQs<\/h2>\n                                                        <\/div>\n                                <\/div>\n\n        <div class=\"faq-section__items\">\n            <div class=\"faq-item wp-block-sb-block-faq-item\" data-faq-item=\"true\">\n        <h5 class=\"faq-item__question\">\n        <button\n            class=\"faq-item__trigger\"\n            type=\"button\"\n            id=\"faq-trigger-13\"\n            aria-expanded=\"false\"\n            aria-controls=\"faq-panel-14\"\n        >\n            <span class=\"faq-item__question-text\">Moet RLS aanstaan op elke Supabase-tabel?<\/span>\n            <svg\n                class=\"faq-item__icon\"\n                width=\"20\"\n                height=\"20\"\n                viewBox=\"0 0 20 20\"\n                aria-hidden=\"true\"\n                focusable=\"false\"\n                xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\n            >\n                <path\n                    d=\"M5 7.5L10 12.5L15 7.5\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"1.75\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                    fill=\"none\"\n                \/>\n            <\/svg>\n        <\/button>\n    <\/h5>\n    <div\n        id=\"faq-panel-14\"\n        class=\"faq-item__panel\"\n        role=\"region\"\n        aria-labelledby=\"faq-trigger-13\"\n        hidden\n    >\n        <div class=\"faq-item__answer\">\n            <p class=\"eplus-wrapper wp-block-paragraph\">Ja, RLS hoort aan te staan op elke Supabase-tabel die de Data API kan bereiken, en standaard horen daar de tabellen in het public-schema bij. De enige veilige uitzondering is een tabel die de browser nooit kan bereiken, bijvoorbeeld in een schema dat niet is opengesteld. Maakt RLS aanzetten een scherm leeg, dan heeft de tabel een policy nodig, niet een uitgeschakelde RLS.<\/p>        <\/div>\n    <\/div>\n<\/div>\n<div class=\"faq-item wp-block-sb-block-faq-item\" data-faq-item=\"true\">\n        <h5 class=\"faq-item__question\">\n        <button\n            class=\"faq-item__trigger\"\n            type=\"button\"\n            id=\"faq-trigger-15\"\n            aria-expanded=\"false\"\n            aria-controls=\"faq-panel-16\"\n        >\n            <span class=\"faq-item__question-text\">Moet ik automatische RLS aanzetten in Supabase?<\/span>\n            <svg\n                class=\"faq-item__icon\"\n                width=\"20\"\n                height=\"20\"\n                viewBox=\"0 0 20 20\"\n                aria-hidden=\"true\"\n                focusable=\"false\"\n                xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\n            >\n                <path\n                    d=\"M5 7.5L10 12.5L15 7.5\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"1.75\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                    fill=\"none\"\n                \/>\n            <\/svg>\n        <\/button>\n    <\/h5>\n    <div\n        id=\"faq-panel-16\"\n        class=\"faq-item__panel\"\n        role=\"region\"\n        aria-labelledby=\"faq-trigger-15\"\n        hidden\n    >\n        <div class=\"faq-item__answer\">\n            <p class=\"eplus-wrapper wp-block-paragraph\">Ja, automatische RLS is een nuttig vangnet, omdat nieuwe tabellen van een AI-codeertool of een migratie dan met RLS aan beginnen. Supabase ondersteunt dit met een PostgreSQL event trigger die RLS aanzet op nieuwe tabellen in het ingestelde schema, volgens de <a href=\"https:\/\/supabase.com\/blog\/supabase-security-2025-retro\" target=\"_blank\" rel=\"noreferrer noopener\">security retro over 2025<\/a>. De trigger past bestaande tabellen niet aan en maakt geen policies. Bestaande tabellen moet u dus nog steeds controleren, en elke nieuwe tabel heeft een eigendomspolicy nodig voordat er klantdata in komt.<\/p>        <\/div>\n    <\/div>\n<\/div>\n<div class=\"faq-item wp-block-sb-block-faq-item\" data-faq-item=\"true\">\n        <h5 class=\"faq-item__question\">\n        <button\n            class=\"faq-item__trigger\"\n            type=\"button\"\n            id=\"faq-trigger-17\"\n            aria-expanded=\"false\"\n            aria-controls=\"faq-panel-18\"\n        >\n            <span class=\"faq-item__question-text\">Is het veilig dat mijn Supabase anon key zichtbaar is in de browser?<\/span>\n            <svg\n                class=\"faq-item__icon\"\n                width=\"20\"\n                height=\"20\"\n                viewBox=\"0 0 20 20\"\n                aria-hidden=\"true\"\n                focusable=\"false\"\n                xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\n            >\n                <path\n                    d=\"M5 7.5L10 12.5L15 7.5\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"1.75\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                    fill=\"none\"\n                \/>\n            <\/svg>\n        <\/button>\n    <\/h5>\n    <div\n        id=\"faq-panel-18\"\n        class=\"faq-item__panel\"\n        role=\"region\"\n        aria-labelledby=\"faq-trigger-17\"\n        hidden\n    >\n        <div class=\"faq-item__answer\">\n            <p class=\"eplus-wrapper wp-block-paragraph\">Ja, de Supabase anon key (de publishable key in nieuwere projecten) is bedoeld om openbaar te zijn, en de Supabase-documentatie over API-keys noemt hem veilig om te tonen. Dat blijft alleen zo zolang RLS aanstaat en de policies eigendom controleren. De service_role-key en secret keys zijn anders: ze omzeilen RLS en mogen nooit in browsercode staan.<\/p>        <\/div>\n    <\/div>\n<\/div>\n<div class=\"faq-item wp-block-sb-block-faq-item\" data-faq-item=\"true\">\n        <h5 class=\"faq-item__question\">\n        <button\n            class=\"faq-item__trigger\"\n            type=\"button\"\n            id=\"faq-trigger-19\"\n            aria-expanded=\"false\"\n            aria-controls=\"faq-panel-20\"\n        >\n            <span class=\"faq-item__question-text\">Maakt RLS mijn app trager?<\/span>\n            <svg\n                class=\"faq-item__icon\"\n                width=\"20\"\n                height=\"20\"\n                viewBox=\"0 0 20 20\"\n                aria-hidden=\"true\"\n                focusable=\"false\"\n                xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\n            >\n                <path\n                    d=\"M5 7.5L10 12.5L15 7.5\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"1.75\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                    fill=\"none\"\n                \/>\n            <\/svg>\n        <\/button>\n    <\/h5>\n    <div\n        id=\"faq-panel-20\"\n        class=\"faq-item__panel\"\n        role=\"region\"\n        aria-labelledby=\"faq-trigger-19\"\n        hidden\n    >\n        <div class=\"faq-item__answer\">\n            <p class=\"eplus-wrapper wp-block-paragraph\">Supabase RLS-policies draaien bij elke query en voegen dus werk toe aan elk verzoek. De Supabase-gids over RLS raadt aan de kolommen te indexeren waarop policies filteren, zoals user_id of tenant_id, en auth.uid() in een select te zetten zodat PostgreSQL het \u00e9\u00e9n keer per statement kan evalueren. Wordt de app trager na het aanzetten van RLS, controleer dan eerst indexen en policy-ontwerp, en zet RLS niet uit.<\/p>        <\/div>\n    <\/div>\n<\/div>\n<div class=\"faq-item wp-block-sb-block-faq-item\" data-faq-item=\"true\">\n        <h5 class=\"faq-item__question\">\n        <button\n            class=\"faq-item__trigger\"\n            type=\"button\"\n            id=\"faq-trigger-21\"\n            aria-expanded=\"false\"\n            aria-controls=\"faq-panel-22\"\n        >\n            <span class=\"faq-item__question-text\">Is RLS genoeg, of heeft mijn backend nog eigen controles nodig?<\/span>\n            <svg\n                class=\"faq-item__icon\"\n                width=\"20\"\n                height=\"20\"\n                viewBox=\"0 0 20 20\"\n                aria-hidden=\"true\"\n                focusable=\"false\"\n                xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\n            >\n                <path\n                    d=\"M5 7.5L10 12.5L15 7.5\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"1.75\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                    fill=\"none\"\n                \/>\n            <\/svg>\n        <\/button>\n    <\/h5>\n    <div\n        id=\"faq-panel-22\"\n        class=\"faq-item__panel\"\n        role=\"region\"\n        aria-labelledby=\"faq-trigger-21\"\n        hidden\n    >\n        <div class=\"faq-item__answer\">\n            <p class=\"eplus-wrapper wp-block-paragraph\">RLS beschermt rijen tegen directe toegang via de Supabase Data API, maar servercode die de service_role-key of security definer-functies gebruikt, slaat RLS over. Die codepaden hebben hun eigen eigendomscontroles nodig. Het algemene herstelpatroon staat in ons artikel over <strong>broken access control<\/strong>.<\/p>        <\/div>\n    <\/div>\n<\/div>\n<div class=\"faq-item wp-block-sb-block-faq-item\" data-faq-item=\"true\">\n        <h5 class=\"faq-item__question\">\n        <button\n            class=\"faq-item__trigger\"\n            type=\"button\"\n            id=\"faq-trigger-23\"\n            aria-expanded=\"false\"\n            aria-controls=\"faq-panel-24\"\n        >\n            <span class=\"faq-item__question-text\">Mijn app werkt en geen klant heeft geklaagd. Waarom zou ik RLS nu controleren?<\/span>\n            <svg\n                class=\"faq-item__icon\"\n                width=\"20\"\n                height=\"20\"\n                viewBox=\"0 0 20 20\"\n                aria-hidden=\"true\"\n                focusable=\"false\"\n                xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\n            >\n                <path\n                    d=\"M5 7.5L10 12.5L15 7.5\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"1.75\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                    fill=\"none\"\n                \/>\n            <\/svg>\n        <\/button>\n    <\/h5>\n    <div\n        id=\"faq-panel-24\"\n        class=\"faq-item__panel\"\n        role=\"region\"\n        aria-labelledby=\"faq-trigger-23\"\n        hidden\n    >\n        <div class=\"faq-item__answer\">\n            <p class=\"eplus-wrapper wp-block-paragraph\">Een werkende app laat niet zien of Supabase RLS klopt. Een test met een eigenaarsaccount toont alleen de eigen data van dat account, en een rij die via de publieke API is gelezen, laat geen zichtbaar spoor na voor de klant van wie die rij is. Een controle voordat er meer klanten bijkomen, laat u gaten dichten voordat persoonsgegevens worden blootgelegd, in plaats van na een mogelijke melding onder AVG artikel 33 of een mislukte securityvragenlijst.<\/p>        <\/div>\n    <\/div>\n<\/div>\n        <\/div>\n\n            <\/section>\n","protected":false},"excerpt":{"rendered":"<p>In een klassieke webapp staat een server tussen de browser en de database, en die server bepaalt wie wat ziet. Als een Supabase-app de database rechtstreeks vanuit de browser bevraagt via de Supabase Data API, staat die server er niet tussen. Dan moet de database zelf beslissen. Supabase RLS (Row Level Security) is die beslissing. [&hellip;]<\/p>\n","protected":false},"author":9,"featured_media":48257,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"related_mode":"latest","related_category":0,"related_post_ids":[],"footnotes":""},"categories":[45],"tags":[],"class_list":["post-49511","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-softwareontwikkeling"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Supabase RLS: Zo Controleert U Uw Vibe-Coded App Op Lekken<\/title>\n<meta name=\"description\" content=\"Supabase RLS bepaalt welke rijen elke gebruiker ziet. Lees vijf RLS-gaten die data kunnen blootleggen in AI-gebouwde apps en wat dat betekent onder de AVG.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/\" \/>\n<meta property=\"og:locale\" content=\"nl_NL\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Supabase RLS: Zo Controleert U Uw Vibe-Coded App Op Lekken\" \/>\n<meta property=\"og:description\" content=\"Supabase RLS bepaalt welke rijen elke gebruiker ziet. Lees vijf RLS-gaten die data kunnen blootleggen in AI-gebouwde apps en wat dat betekent onder de AVG.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/\" \/>\n<meta property=\"og:site_name\" content=\"Sunbytes\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/sunbytes\/\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-29T13:47:25+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-29T13:49:47+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/Why-is-refactoring-the-default-for-most-AI-built-apps.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1125\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"Thien Le\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Geschreven door\" \/>\n\t<meta name=\"twitter:data1\" content=\"Thien Le\" \/>\n\t<meta name=\"twitter:label2\" content=\"Geschatte leestijd\" \/>\n\t<meta name=\"twitter:data2\" content=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/#organization\",\"name\":\"Sunbytes\",\"url\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"nl-NL\",\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/sunbytes.io\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/SUNBYTES-LOGO.svg\",\"contentUrl\":\"https:\\\/\\\/sunbytes.io\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/SUNBYTES-LOGO.svg\",\"width\":120,\"height\":30,\"caption\":\"Sunbytes\"},\"image\":{\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/sunbytes\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/sunbytes-accelerate-workforce-solutions\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/sunbytes\\\/\"],\"knowsAbout\":[\"HR Solutions\",\"Payroll service\",\"EOR service\",\"Tech services\",\"Security services\"]},{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/\"},\"author\":{\"name\":\"Thien Le\",\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/#\\\/schema\\\/person\\\/edb46097c22381bf08caa3b6a0713677\"},\"headline\":\"Supabase RLS: hoe vibe-coded apps data kunnen lekken en hoe u dat controleert\",\"datePublished\":\"2026-10-29T13:47:25+00:00\",\"dateModified\":\"2026-10-29T13:49:47+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/\"},\"wordCount\":3069,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/sunbytes.io\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/Why-is-refactoring-the-default-for-most-AI-built-apps.webp\",\"articleSection\":[\"Softwareontwikkeling\"],\"inLanguage\":\"nl-NL\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/\",\"url\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/\",\"name\":\"Supabase RLS: Zo Controleert U Uw Vibe-Coded App Op Lekken\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/sunbytes.io\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/Why-is-refactoring-the-default-for-most-AI-built-apps.webp\",\"datePublished\":\"2026-10-29T13:47:25+00:00\",\"dateModified\":\"2026-10-29T13:49:47+00:00\",\"description\":\"Supabase RLS bepaalt welke rijen elke gebruiker ziet. Lees vijf RLS-gaten die data kunnen blootleggen in AI-gebouwde apps en wat dat betekent onder de AVG.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/#breadcrumb\"},\"inLanguage\":\"nl-NL\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"nl-NL\",\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/#primaryimage\",\"url\":\"https:\\\/\\\/sunbytes.io\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/Why-is-refactoring-the-default-for-most-AI-built-apps.webp\",\"contentUrl\":\"https:\\\/\\\/sunbytes.io\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/Why-is-refactoring-the-default-for-most-AI-built-apps.webp\",\"width\":2000,\"height\":1125,\"caption\":\"RLS: hoe vibe-coded apps data kunnen lekken en hoe u dat controleert\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/softwareontwikkeling\\\/supabase-rls-ai-built-apps\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Supabase RLS: hoe vibe-coded apps data kunnen lekken en hoe u dat controleert\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/#website\",\"url\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/\",\"name\":\"Sunbytes\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"nl-NL\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/#\\\/schema\\\/person\\\/edb46097c22381bf08caa3b6a0713677\",\"name\":\"Thien Le\",\"pronouns\":\"She\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"nl-NL\",\"@id\":\"https:\\\/\\\/sunbytes.io\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/Sunbytes0976-150x150.webp\",\"url\":\"https:\\\/\\\/sunbytes.io\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/Sunbytes0976-150x150.webp\",\"contentUrl\":\"https:\\\/\\\/sunbytes.io\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/Sunbytes0976-150x150.webp\",\"caption\":\"Thien Le\"},\"description\":\"Thien Le is a B2B content writer with more than four years of experience in crafting compelling B2B content for a global audience, specializing in how people, technology, and business operations come together. At Sunbytes, she plans, connects insights from HR experts, edits, and uses technology to improve content quality. Her content helps readers cut through complexity and find practical information for hiring, paying, and managing people across borders.\",\"url\":\"https:\\\/\\\/sunbytes.io\\\/nl\\\/blog\\\/author\\\/thien-le\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Supabase RLS: Zo Controleert U Uw Vibe-Coded App Op Lekken","description":"Supabase RLS bepaalt welke rijen elke gebruiker ziet. Lees vijf RLS-gaten die data kunnen blootleggen in AI-gebouwde apps en wat dat betekent onder de AVG.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/","og_locale":"nl_NL","og_type":"article","og_title":"Supabase RLS: Zo Controleert U Uw Vibe-Coded App Op Lekken","og_description":"Supabase RLS bepaalt welke rijen elke gebruiker ziet. Lees vijf RLS-gaten die data kunnen blootleggen in AI-gebouwde apps en wat dat betekent onder de AVG.","og_url":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/","og_site_name":"Sunbytes","article_publisher":"https:\/\/www.facebook.com\/sunbytes\/","article_published_time":"2026-10-29T13:47:25+00:00","article_modified_time":"2026-10-29T13:49:47+00:00","og_image":[{"width":2000,"height":1125,"url":"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/Why-is-refactoring-the-default-for-most-AI-built-apps.webp","type":"image\/webp"}],"author":"Thien Le","twitter_card":"summary_large_image","twitter_misc":{"Geschreven door":"Thien Le","Geschatte leestijd":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Organization","@id":"https:\/\/sunbytes.io\/nl\/#organization","name":"Sunbytes","url":"https:\/\/sunbytes.io\/nl\/","logo":{"@type":"ImageObject","inLanguage":"nl-NL","@id":"https:\/\/sunbytes.io\/nl\/#\/schema\/logo\/image\/","url":"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/08\/SUNBYTES-LOGO.svg","contentUrl":"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/08\/SUNBYTES-LOGO.svg","width":120,"height":30,"caption":"Sunbytes"},"image":{"@id":"https:\/\/sunbytes.io\/nl\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/sunbytes\/","https:\/\/www.linkedin.com\/company\/sunbytes-accelerate-workforce-solutions\/","https:\/\/www.linkedin.com\/company\/sunbytes\/"],"knowsAbout":["HR Solutions","Payroll service","EOR service","Tech services","Security services"]},{"@type":"Article","@id":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/#article","isPartOf":{"@id":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/"},"author":{"name":"Thien Le","@id":"https:\/\/sunbytes.io\/nl\/#\/schema\/person\/edb46097c22381bf08caa3b6a0713677"},"headline":"Supabase RLS: hoe vibe-coded apps data kunnen lekken en hoe u dat controleert","datePublished":"2026-10-29T13:47:25+00:00","dateModified":"2026-10-29T13:49:47+00:00","mainEntityOfPage":{"@id":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/"},"wordCount":3069,"commentCount":0,"publisher":{"@id":"https:\/\/sunbytes.io\/nl\/#organization"},"image":{"@id":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/#primaryimage"},"thumbnailUrl":"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/Why-is-refactoring-the-default-for-most-AI-built-apps.webp","articleSection":["Softwareontwikkeling"],"inLanguage":"nl-NL","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/","url":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/","name":"Supabase RLS: Zo Controleert U Uw Vibe-Coded App Op Lekken","isPartOf":{"@id":"https:\/\/sunbytes.io\/nl\/#website"},"primaryImageOfPage":{"@id":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/#primaryimage"},"image":{"@id":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/#primaryimage"},"thumbnailUrl":"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/Why-is-refactoring-the-default-for-most-AI-built-apps.webp","datePublished":"2026-10-29T13:47:25+00:00","dateModified":"2026-10-29T13:49:47+00:00","description":"Supabase RLS bepaalt welke rijen elke gebruiker ziet. Lees vijf RLS-gaten die data kunnen blootleggen in AI-gebouwde apps en wat dat betekent onder de AVG.","breadcrumb":{"@id":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/#breadcrumb"},"inLanguage":"nl-NL","potentialAction":[{"@type":"ReadAction","target":["https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/"]}]},{"@type":"ImageObject","inLanguage":"nl-NL","@id":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/#primaryimage","url":"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/Why-is-refactoring-the-default-for-most-AI-built-apps.webp","contentUrl":"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/10\/Why-is-refactoring-the-default-for-most-AI-built-apps.webp","width":2000,"height":1125,"caption":"RLS: hoe vibe-coded apps data kunnen lekken en hoe u dat controleert"},{"@type":"BreadcrumbList","@id":"https:\/\/sunbytes.io\/nl\/blog\/softwareontwikkeling\/supabase-rls-ai-built-apps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/sunbytes.io\/nl\/"},{"@type":"ListItem","position":2,"name":"Supabase RLS: hoe vibe-coded apps data kunnen lekken en hoe u dat controleert"}]},{"@type":"WebSite","@id":"https:\/\/sunbytes.io\/nl\/#website","url":"https:\/\/sunbytes.io\/nl\/","name":"Sunbytes","description":"","publisher":{"@id":"https:\/\/sunbytes.io\/nl\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/sunbytes.io\/nl\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"nl-NL"},{"@type":"Person","@id":"https:\/\/sunbytes.io\/nl\/#\/schema\/person\/edb46097c22381bf08caa3b6a0713677","name":"Thien Le","pronouns":"She","image":{"@type":"ImageObject","inLanguage":"nl-NL","@id":"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/08\/Sunbytes0976-150x150.webp","url":"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/08\/Sunbytes0976-150x150.webp","contentUrl":"https:\/\/sunbytes.io\/wp-content\/uploads\/2026\/08\/Sunbytes0976-150x150.webp","caption":"Thien Le"},"description":"Thien Le is a B2B content writer with more than four years of experience in crafting compelling B2B content for a global audience, specializing in how people, technology, and business operations come together. At Sunbytes, she plans, connects insights from HR experts, edits, and uses technology to improve content quality. Her content helps readers cut through complexity and find practical information for hiring, paying, and managing people across borders.","url":"https:\/\/sunbytes.io\/nl\/blog\/author\/thien-le\/"}]}},"_links":{"self":[{"href":"https:\/\/sunbytes.io\/nl\/wp-json\/wp\/v2\/posts\/49511","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sunbytes.io\/nl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sunbytes.io\/nl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sunbytes.io\/nl\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/sunbytes.io\/nl\/wp-json\/wp\/v2\/comments?post=49511"}],"version-history":[{"count":8,"href":"https:\/\/sunbytes.io\/nl\/wp-json\/wp\/v2\/posts\/49511\/revisions"}],"predecessor-version":[{"id":49543,"href":"https:\/\/sunbytes.io\/nl\/wp-json\/wp\/v2\/posts\/49511\/revisions\/49543"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sunbytes.io\/nl\/wp-json\/wp\/v2\/media\/48257"}],"wp:attachment":[{"href":"https:\/\/sunbytes.io\/nl\/wp-json\/wp\/v2\/media?parent=49511"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sunbytes.io\/nl\/wp-json\/wp\/v2\/categories?post=49511"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sunbytes.io\/nl\/wp-json\/wp\/v2\/tags?post=49511"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}