{"slug": "test-your-supabase-rls-before-you-ship-a-free-red-green-fixture-and-the-9-sql-a", "title": "Test your Supabase RLS before you ship: a free red/green fixture and the 9 SQL checks a linter cannot run", "summary": "A developer has released a free red/green fixture and a set of nine SQL checks to help Supabase developers test row-level security (RLS) policies before shipping. The fixture, available on GitHub, runs PostgreSQL in PGlite locally and demonstrates cross-user data leaks, while the audit queries inspect system catalogs for common RLS misconfigurations. The developer warns that linters only check policy existence, not correctness, and provides a coverage query to identify tables with RLS disabled.", "body_md": "If you built a Supabase app quickly - with an AI coding tool or by hand - the row-level-security policies were often written last, or generated for you. That is fine. What is not fine is shipping without knowing whether those policies actually isolate one user's rows from another.\n\nSupabase ships a database linter, and you should run it first - it is free and it catches the obvious cases: RLS switched off, and RLS switched on with no policy behind it. But a linter checks whether a policy *exists*, not whether the policy is *correct*. Those are different questions, and the second one is where cross-user leaks live.\n\nI put a minimal, synthetic reproduction on GitHub: [ supabase-rls-leak-demo](https://github.com/cekuu35/supabase-rls-leak-demo). Same test suite on two branches, differing only by\n\n`db/policies.sql`\n\n:`broken`\n\n-> `fixed`\n\n-> \n\n```\nnpm ci\nnpm run test:ci\n```\n\nNo Docker, no Supabase project, no credentials. The tests run PostgreSQL in PGlite locally and exercise database-level row security. They do not model Supabase Auth, PostgREST, the Data API, or the network path - the result proves only the row-level gate in the fixture, which is exactly the gate people get wrong.\n\nOn `broken`\n\n, the failing assertion is readable on purpose:\n\n``` php\nx does not let user B read any row owned by user A\n  -> user B received 1 row(s) belonging to another user:\n    [\"A: card ending 4471, expiry 09/29\"]\n```\n\n(That is synthetic seed data, not a real card.)\n\nThe repo also ships `audit/rls-audit.sql`\n\n- nine read-only queries against the system catalogs, MIT-licensed, nothing to install and nothing to send anywhere. Every one is `SELECT`\n\n-only, so it is safe to paste into the Supabase SQL editor. They tell you:\n\n`TO`\n\nclause, so the policy is evaluated for `anon`\n\ntoo)`anon`\n\nand `authenticated`\n\ncan `INSERT`\n\n/ `UPDATE`\n\n/ `DELETE`\n\n`SECURITY DEFINER`\n\nfunctions the client can call, and whether `search_path`\n\nis pinned`FORCE ROW LEVEL SECURITY`\n\n, and roles holding `BYPASSRLS`\n\nHere is the coverage query on its own, so you can try it right now:\n\n```\nselect\n  c.relname as table_name,\n  c.relrowsecurity as rls_enabled,\n  count(p.polname) as policy_count\nfrom pg_class c\njoin pg_namespace n on n.oid = c.relnamespace\nleft join pg_policy p on p.polrelid = c.oid\nwhere n.nspname = 'public' and c.relkind = 'r'\ngroup by c.relname, c.relrowsecurity\norder by c.relrowsecurity, c.relname;\n```\n\nAny row with `rls_enabled = false`\n\nis a table where PostgreSQL applies no RLS row filter to roles subject to RLS. Investigate grants, role attributes and API/schema exposure before calling it an externally reachable leak - `policy_count > 0`\n\ndoes not by itself prove one.\n\nTesting \"as a user\" by hand usually goes like this:\n\n```\nset role authenticated;\nselect * from notes;   -- returns nothing, so you assume the policy is broken\n```\n\nBut `set role authenticated`\n\non its own leaves `request.jwt.claims`\n\nunset, so `auth.uid()`\n\nreturns `NULL`\n\n, every ownership policy filters everything away, and you conclude a correct policy is broken. The audit's role-simulation harness wraps its probes in `BEGIN ... ROLLBACK`\n\nand sets the JWT claims the way the API does, so you can query as a real user without persisting anything.\n\nReading a policy against the schema it guards is manual work. The failure modes that survive review and pass tests are the ones a query cannot flag:\n\n`service_role`\n\nkey reachable from a client code pathThat reading is the audit. If you want to do it yourself, the [Supabase RLS Audit Kit](https://cengokurtoglu.gumroad.com/l/supabase-rls-audit-kit?utm_source=devto&utm_medium=article&utm_campaign=rls_kit&utm_content=rls_devto) is seven commented SQL audits you run against your own catalogs ($29, nothing leaves your database). If you just want a plain go-live pass wider than RLS - secrets, auth, performance, SEO, reliability, backups - the [Next.js + Supabase Launch Checklist](https://cengokurtoglu.gumroad.com/l/xjnmxt?utm_source=devto&utm_medium=article&utm_campaign=launch_checklist&utm_content=rls_devto) is an 8-page, 60-check PDF ($19). And if you would rather have it done, I run a fixed-price [Supabase RLS Security Audit](https://www.upwork.com/services/product/2083862107074689176?utm_source=devto&utm_medium=article&utm_campaign=rls_audit&utm_content=rls_devto) from $99.\n\nAll three are review aids for projects you own or are authorized to test - not a penetration test, a certification, or a guarantee that an application is secure. But the free fixture and the nine queries above are genuinely all most people need before launch. Start there, and if they come back clean, you are done.", "url": "https://wpnews.pro/news/test-your-supabase-rls-before-you-ship-a-free-red-green-fixture-and-the-9-sql-a", "canonical_source": "https://dev.to/cekuu35/test-your-supabase-rls-before-you-ship-a-free-redgreen-fixture-and-the-9-sql-checks-a-linter-388d", "published_at": "2026-08-12 00:44:55+00:00", "updated_at": "2026-08-12 01:15:21.452698+00:00", "lang": "en", "topics": ["developer-tools", "ai-products"], "entities": ["Supabase", "PostgreSQL", "PGlite", "GitHub", "Cengokurtoglu"], "alternates": {"html": "https://wpnews.pro/news/test-your-supabase-rls-before-you-ship-a-free-red-green-fixture-and-the-9-sql-a", "markdown": "https://wpnews.pro/news/test-your-supabase-rls-before-you-ship-a-free-red-green-fixture-and-the-9-sql-a.md", "text": "https://wpnews.pro/news/test-your-supabase-rls-before-you-ship-a-free-red-green-fixture-and-the-9-sql-a.txt", "jsonld": "https://wpnews.pro/news/test-your-supabase-rls-before-you-ship-a-free-red-green-fixture-and-the-9-sql-a.jsonld"}}