Sensitive columns are not readable through the API on publicly readable tables
Why it matters
RLS filters rows, never columns. When a table is readable by anon or by every signed-in user (a waived USING (true) policy, or any read policy that is not tied to the caller), every column of every row comes back from the REST endpoint with a plain select=*. Supabase also grants table-level privileges on new public tables to anon and authenticated by default, so the only things that hide a column are a column-level grant, a separate owner-only table, or a non-exposed schema. AI-built apps routinely put a password_hash, api_key, stripe_customer_id, phone, date_of_birth, or email column on the same profiles or users table they marked public for the leaderboard, so one anonymous GET dumps every user's secrets and personal data. The Supabase database advisor flags this class as lint 0023, sensitive columns exposed. This check judges what anon and authenticated can actually read after column grants and views are taken into account.
Severity rationale
Critical because a sensitive column on a publicly readable table is exfiltrated with one unauthenticated GET, exposing credentials or personal data for every row at once.
Remediation
Take the sensitive column out of what the API role can read. The cleanest fix is a separate table: keep public fields in public.profiles and move secrets to public.profile_secrets with owner-only RLS (or to a schema that is not exposed). To keep one table, revoke the table-level grant and grant only the safe columns:
revoke select on public.profiles from anon, authenticated;
grant select (id, username, avatar_url) on public.profiles to anon, authenticated;
Column privileges only take effect once the table-level grant is revoked, and clients must then name their columns (select=id,username) because select=* fails with permission denied. Do not hide a column behind a view unless the view omits it AND the base table is no longer readable by anon and authenticated.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Supabase RLS & Keys audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe:4.14 · CWE-284 — Improper Access Control
- cwe:4.14 · CWE-285 — Improper Authorization
- cwe:4.14 · CWE-200 — Exposure of Sensitive Information to an Unauthorized Actor
- owasp:2021 · A01 — Broken Access Control
- external · 0023_sensitive_columns_exposed — Supabase database advisor lint 0023 sensitive columns exposed
Taxons
History
- 2026-10-03·v1.0.0·Initial supabase-rls-keys v1 authoring; sensitive-column readability on publicly readable tables, accounting for column grants and views.·by supabase-rls-keys-v1-build