<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nightshift Scan</title>
    <description>The latest articles on DEV Community by Nightshift Scan (@nightshiftscan).</description>
    <link>https://dev.to/nightshiftscan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4187482%2F627cf5b5-e44e-4a48-b7f9-9141d854bce7.png</url>
      <title>DEV Community: Nightshift Scan</title>
      <link>https://dev.to/nightshiftscan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nightshiftscan"/>
    <language>en</language>
    <item>
      <title>Three Supabase RLS settings worth checking before launch</title>
      <dc:creator>Nightshift Scan</dc:creator>
      <pubDate>Wed, 21 Oct 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/nightshiftscan/three-supabase-rls-settings-worth-checking-before-launch-3684</link>
      <guid>https://dev.to/nightshiftscan/three-supabase-rls-settings-worth-checking-before-launch-3684</guid>
      <description>&lt;p&gt;Three database settings are worth checking in a Supabase project. Here is what each one means and a read-only query to find it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Tables with RLS disabled
&lt;/h2&gt;

&lt;p&gt;Anyone with your project's public anon (or publishable) key (it ships in your frontend) may be able to read or change them through the API, depending on your grants.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select n.nspname as schema, c.relname as table_name&lt;br&gt;
from pg_class c join pg_namespace n on n.oid = c.relnamespace&lt;br&gt;
where n.nspname = 'public' and c.relkind in ('r','p') and not c.relrowsecurity;&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  

&lt;ol&gt;
&lt;li&gt;Policies with &lt;code&gt;using (true)&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/h2&gt;


&lt;p&gt;Fine for public data, risky for per-user rows.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select schemaname, tablename, policyname, cmd&lt;br&gt;
from pg_policies&lt;br&gt;
where schemaname = 'public' and permissive = 'PERMISSIVE'&lt;br&gt;
  and (qual = 'true' or with_check = 'true');&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  

&lt;ol&gt;
&lt;li&gt;Views without &lt;code&gt;security_invoker = true&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/h2&gt;


&lt;p&gt;They run with the owner's rights and may bypass RLS on the underlying tables.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select n.nspname as schema, c.relname as view_name&lt;br&gt;
from pg_class c join pg_namespace n on n.oid = c.relnamespace&lt;br&gt;
where n.nspname = 'public' and c.relkind = 'v'&lt;br&gt;
  and not exists (select 1 from unnest(coalesce(c.reloptions, '{}'::text[])) o&lt;br&gt;
                  where lower(o) in ('security_invoker=true','security_invoker=on',&lt;br&gt;
                                    'security_invoker=yes','security_invoker=1'));&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  How to read the output&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Each row is something to review, not a verdict. A &lt;code&gt;using (true)&lt;/code&gt; policy on a public lookup table can be intended. On a table holding per-user rows, it usually isn't what you want. Also review policies like &lt;code&gt;auth.uid() is not null&lt;/code&gt; or &lt;code&gt;auth.role() = 'authenticated'&lt;/code&gt;: they let every logged-in user read every row, and this check doesn't flag them. For views, &lt;code&gt;alter view ... set (security_invoker = true);&lt;/code&gt; makes them respect the caller's RLS (Postgres 15+).&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;p&gt;These are read-only catalog checks only. They don't test your live app, API, Edge Functions or storage, and a clean result doesn't show there are no issues. Only the &lt;code&gt;public&lt;/code&gt; schema is checked; other schemas you expose through the API aren't. Materialized views aren't covered by these three queries (RLS doesn't apply to them); the full script lists them. Supabase's own Security Advisor already flags RLS-disabled tables and security-definer views; these queries are a companion to it, not a replacement. Run them only on a database you own or are authorised to access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it matters
&lt;/h2&gt;

&lt;p&gt;UpGuard research found 16,326 Supabase databases with tables readable from the public internet, among about 300,000 domains showing signs of Supabase use. Over half had signs of personal data in their table structure. UpGuard attributes it mainly to project configuration, such as missing or overly broad row-level security. Source: UpGuard, "Everything Everywhere: Systemic Data Exposure in Supabase Apps" (upguard.com/blog/everything-everywhere-systemic-data-exposure-in-supabase-apps).&lt;/p&gt;

&lt;p&gt;Full script, these three checks plus one for materialized views in a single read-only SELECT: &lt;a href="https://github.com/nightshiftscan/supabase-rls-self-check" rel="noopener noreferrer"&gt;https://github.com/nightshiftscan/supabase-rls-self-check&lt;/a&gt; (Apache-2.0)&lt;/p&gt;

&lt;p&gt;More: nightshiftscan.com&lt;/p&gt;

&lt;p&gt;Nightshift Scan · &lt;a href="mailto:hello@nightshiftscan.com"&gt;hello@nightshiftscan.com&lt;/a&gt; · Legal notice: &lt;a href="https://nightshiftscan.com/privacy#legal-notice" rel="noopener noreferrer"&gt;https://nightshiftscan.com/privacy#legal-notice&lt;/a&gt;&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>postgres</category>
      <category>database</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
