Run this read-only SQL query in your Supabase project to inventory tables in the public schema and flag three conditions worth reviewing: row-level security (RLS) is off, RLS is on but there are no policies, or a policy contains a literal true expression. These are triage signals, not proof that an app is exploitable. The query reads PostgreSQL catalogs; it does not change tables, grants, policies, or data.
Run the read-only table inventory
Use a trusted database console or diagnostic connection scoped to the intended project. Supabase recommends read-only access for diagnostics; its MCP documentation describes read_only=true as running queries as a read-only Postgres user. Do not run an unfamiliar query against a production project with write privileges when read-only access is available.
As an Amazon Associate I earn from qualifying purchases.
select
n.nspname as schema_name,
c.relname as table_name,
c.relrowsecurity as rls_enabled,
coalesce(p.policy_count, 0) as policy_count,
coalesce(p.always_true_policy_count, 0) as always_true_policy_count,
p.policy_summary
from pg_class as c
join pg_namespace as n
on n.oid = c.relnamespace
left join lateral (
select
count(*) as policy_count,
count(*) filter (
where trim(coalesce(pol.polqual::text, '')) = 'true'
or trim(coalesce(pol.polwithcheck::text, '')) = 'true'
) as always_true_policy_count,
string_agg(
format('%I (%s; roles: %s)', pol.polname, pol.polcmd,
array_to_string(pol.polroles::regrole[], ', ')),
'; ' order by pol.polname
) as policy_summary
from pg_policy as pol
where pol.polrelid = c.oid
) as p on true
where n.nspname = 'public'
and c.relkind in ('r', 'p')
order by c.relname;
The results include ordinary and partitioned tables in public. Each row shows whether RLS is enabled, how many policies are attached, how many contain an expression rendered exactly as true, and a summary of policy names, commands, and roles.
Recommended Free Tools
Interpret the three flags carefully
RLS is disabled
rls_enabled = false means the table does not have RLS enabled. Supabase warns that tables in exposed schemas without RLS can be read or written by roles that already have table grants. Review the table’s exposure and grants promptly; this result alone does not show which roles can reach it.
#1 Best Overall
RLS is enabled, but no policies are present
rls_enabled = true with policy_count = 0 merits a check against the intended access model. RLS with no applicable policy can deny access, including access the app expected to allow; it does not by itself mean the table is publicly readable.
A policy contains a literal always-true expression
always_true_policy_count > 0 identifies policies whose catalog condition is exactly true in either the row-visibility expression or the write check. Inspect each named policy’s command and target roles. An always-true condition can allow all rows for the roles and operations covered, but whether that is a mistake depends on the intended behavior.
Rank #2
This detector is intentionally narrow: it catches expressions rendered exactly as true. A zero count does not establish that policies are restrictive; a more complex expression may still be permissive. Catalog output also cannot tell you whether a policy matches the product’s requirements. Verify the query’s behavior against the project’s PostgreSQL version and catalog behavior before relying on it operationally.
Review grants and policies together
Grants and RLS policies do different jobs. PostgreSQL checks table privileges and then RLS policies when a client accesses a table. Adding policies does not revoke existing grants, so examine which roles can perform which operations and whether the policies constrain those operations as intended. In Supabase, pay particular attention to anon, authenticated, and service_role; access should be limited to what the application needs. See Supabase’s Securing your data and Row Level Security documentation.
Rank #3
Check schemas and access paths this query omits
Other API-exposed schemas
The filter n.nspname = 'public' limits this inventory to public. If the Data API exposes another schema, adapt the filter to include that schema and review its tables too. A clean result for public is not a project-wide audit.
Views and functions
This query inventories tables, not views or functions. Supabase documents that views can bypass RLS by default and that security-definer functions in exposed schemas need careful handling. Review those paths separately rather than inferring their safety from the table results; see the data security guidance.
Rank #4
Keys in frontend code and build artifacts
A database catalog query cannot reveal whether a builder placed a secret in browser code, a repository, or build output. Supabase publishable keys are intended for shipped client code when RLS and least-privilege access are configured. Secret and service-role keys bypass RLS and belong only in controlled backend components. Search source and deployed build artifacts for key handling, and follow Supabase’s guidance: API keys and Securing your data.
Use the inventory as one input to verification
Supabase’s Security Advisor offers deterministic checks in Studio, MCP, CLI, and the Management API. Treat its findings as prompts for review, not automatic instructions to change a schema: some configurations may be intentional. Compare each finding with the intended schema and access model using the Advisors documentation.
Best Value
Then test actual behavior across the roles and operations the app uses. Supabase recommends database tests that assert both expected allow and expected deny cases. A metadata inventory can identify configuration patterns, but only a behavior check can confirm that the app’s access rules work as intended.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




