react-doctor/supabase-rls-policy-risk
A Supabase policy that disables row-level security, exposes the service role, or uses a `(true)` write predicate lets clients read or modify data that is not theirs.
- Category: Security
- Severity: error
- Source:
oxlint-plugin-react-doctor - Framework: global
- Enabled when: SQL files only — *.sql and supabase/migrations/ or supabase/schemas/ paths
- Tags: security-scan
- Default: Enabled
Validation prompt
Use this to decide whether a fired diagnostic is real or a false positive.
Fires on Supabase/Postgres SQL (.sql files, or supabase/migrations/supabase/schemas paths) in four shapes: an ALTER TABLE … DISABLE ROW LEVEL SECURITY; a CREATE POLICY … auth.role() = 'service_role' (a service-role bypass exposed to client roles); a CREATE POLICY … FOR ALL|INSERT|UPDATE|DELETE … USING|WITH CHECK (true) (an unconditional write policy); or any non-FOR SELECT CREATE POLICY … USING|WITH CHECK (true) (an implicit open policy). An explicit FOR SELECT … (true) public-read policy is intentionally NOT flagged. FALSE POSITIVE: a deliberately public table where even writes are meant to be open (rare), or a migration that loosens then re-tightens the policy in a later statement — check the table's final policy state.
Fix prompt
Use this once validation confirms the diagnostic is real.
Replace (true) write predicates with ownership or membership checks: USING (auth.uid() = user_id) plus a matching WITH CHECK, and for multi-tenant data join a trusted membership table instead of trusting a client-supplied column. Never DISABLE ROW LEVEL SECURITY on a client-reachable table, and keep the service_role key on the server, because it already bypasses RLS. Scope public reads with an explicit FOR SELECT policy so writes stay locked.
Related rules
More Security rules from the rules reference:
react-doctor/supabase-table-missing-rls: Supabase table created without Row Level Securityreact-doctor/svg-filter-clickjacking-risk: Applying CSS or SVG filters over a cross-origin iframe can be used for clickjacking or to read pixels from framed content the attacker should not see.react-doctor/tanstack-start-get-mutation: Use `createServerFn({ method: 'POST' })` for data modifications — GET requests can be triggered by prefetching and are vulnerable to CSRFreact-doctor/tanstack-start-no-secrets-in-loader: Loaders are isomorphic (run on both server and client). Wrap secret access in `createServerFn()` so it stays server-onlyreact-doctor/tenant-static-proxy-risk: Building an asset path from a client-supplied tenant, subdomain, or workspace value lets one tenant read another tenant's files.