<?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>Forem: Fabio</title>
    <description>The latest articles on Forem by Fabio (@fabio_a26a4e58d4163919a53).</description>
    <link>https://forem.com/fabio_a26a4e58d4163919a53</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3812388%2F4aa1c040-9002-4442-89d3-b4f486ab84e2.png</url>
      <title>Forem: Fabio</title>
      <link>https://forem.com/fabio_a26a4e58d4163919a53</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/fabio_a26a4e58d4163919a53"/>
    <language>en</language>
    <item>
      <title>Supabase Security: The Hidden Dangers of RLS and How to Audit Your API 🛡️</title>
      <dc:creator>Fabio</dc:creator>
      <pubDate>Sun, 08 Mar 2026 20:45:00 +0000</pubDate>
      <link>https://forem.com/fabio_a26a4e58d4163919a53/supabase-security-the-hidden-dangers-of-rls-and-how-to-audit-your-api-29e9</link>
      <guid>https://forem.com/fabio_a26a4e58d4163919a53/supabase-security-the-hidden-dangers-of-rls-and-how-to-audit-your-api-29e9</guid>
      <description>&lt;p&gt;Supabase has solidified itself as the developer's favorite Open Source alternative to Firebase. The promise is incredible: you build a relational PostgreSQL database and magically get an instant REST API (via PostgREST) ready to be consumed by your frontend.&lt;/p&gt;

&lt;p&gt;But exactly in this "magic" lies the danger.&lt;/p&gt;

&lt;p&gt;The convenience of having an API that directly reflects your database schema brings a massive cyber risk if you ignore (or misconfigure) the heart of Supabase security: &lt;strong&gt;RLS (Row Level Security)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we'll break down how data leaks happen and how you can automate the pentesting of your application before going to production.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛑 The Problem: The Default Trap
&lt;/h2&gt;

&lt;p&gt;In traditional APIs (Node.js, Laravel, Spring), security lives in the backend. You write middlewares and controllers to block unauthorized access. &lt;/p&gt;

&lt;p&gt;In Supabase, the logic is inverted: &lt;strong&gt;access control lives inside PostgreSQL&lt;/strong&gt;. The database acts as the bouncer, evaluating RLS rules row by row. &lt;/p&gt;

&lt;p&gt;The main issue? &lt;strong&gt;By default, when you create a new table, RLS is disabled.&lt;/strong&gt; This means the table is 100% public. Anyone with access to "Inspect Element" on your site can grab your &lt;code&gt;anon_key&lt;/code&gt;, send a simple &lt;code&gt;GET&lt;/code&gt; request, and dump your entire database.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐛 The 3 Most Common RLS Mistakes
&lt;/h2&gt;

&lt;p&gt;Even when developers remember to enable RLS, logical flaws often leave the castle gates wide open:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The "Just Make It Work" Policy
&lt;/h3&gt;

&lt;p&gt;Desperate to make the frontend render data, many devs create a &lt;code&gt;SELECT&lt;/code&gt; policy with the expression &lt;code&gt;true&lt;/code&gt;. &lt;br&gt;
The result? You protected the edits, but reading is wide open. User data, emails, balances, and histories are exposed to any web scraper or bot.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The "Ghost Auth" Flaw
&lt;/h3&gt;

&lt;p&gt;Does your API require the user to be authenticated (&lt;code&gt;auth.role() = 'authenticated'&lt;/code&gt;)? Great. But did you enable &lt;strong&gt;Email Confirmations&lt;/strong&gt; in the Supabase dashboard?&lt;br&gt;
If not, an attacker doesn't need to steal an account. They simply send a &lt;code&gt;POST /auth/v1/signup&lt;/code&gt; forging a fake email and receive a valid JWT. To your RLS, they are now a "legitimate" user roaming freely through protected routes.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Mass Assignment (Privilege Escalation)
&lt;/h3&gt;

&lt;p&gt;If your &lt;code&gt;users&lt;/code&gt; table allows &lt;code&gt;UPDATE&lt;/code&gt; (PATCH) requests for the profile owner, what prevents a malicious user from intercepting the request and injecting an extra column into the JSON payload?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "Hacker",
  "is_admin": true,
  "role": "superuser"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If your policies don't restrict &lt;em&gt;which&lt;/em&gt; columns can be modified, a standard user becomes an admin with a single HTTP request.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠️ How to audit your own API?
&lt;/h2&gt;

&lt;p&gt;Testing this manually is painful. It requires capturing keys, forging JWTs, opening Postman, crafting payloads, and testing method by method. Not to mention the risk of running a &lt;code&gt;DELETE&lt;/code&gt; test and accidentally wiping out production data.&lt;/p&gt;

&lt;p&gt;This is where DAST (Dynamic Application Security Testing) tools come in. The most direct and specialized solution for this ecosystem today is &lt;strong&gt;&lt;a href="https://supasec.dev/" rel="noopener noreferrer"&gt;SupaSec&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Meet SupaSec
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://supasec.dev/" rel="noopener noreferrer"&gt;SupaSec&lt;/a&gt; acts as a pentest framework strictly focused on PostgREST quirks. You just input your web app's URL, and it does the dirty work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automated Reconnaissance:&lt;/strong&gt; It scans your frontend JavaScript bundles, extracts your Supabase URL and public &lt;code&gt;anon_key&lt;/code&gt;, and discovers hidden tables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ghost Auth Exploitation:&lt;/strong&gt; The tool automatically tests if your API allows the creation of unconfirmed users to bypass anonymous RLS rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Dumper:&lt;/strong&gt; Tests the resilience of your &lt;code&gt;SELECT&lt;/code&gt; policies by trying to extract records, bypassing pagination limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe Exploit Mode (Dry-Run):&lt;/strong&gt; This is a killer feature. You can manually test malicious &lt;code&gt;PATCH&lt;/code&gt; or &lt;code&gt;DELETE&lt;/code&gt; requests directly from the UI safely. SupaSec injects a native Supabase HTTP header (&lt;code&gt;Prefer: tx=rollback, return=representation&lt;/code&gt;). This instructs the API to receive your malicious payload, evaluate the RLS rules, return the success/failure result, and then &lt;strong&gt;rollback the database transaction&lt;/strong&gt; in milliseconds—leaving 0 traces and altering exactly zero bytes of production data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ✅ Security Checklist (Do It Today)
&lt;/h2&gt;

&lt;p&gt;Don't wait for a data breach to review your architecture. Open your Supabase dashboard right now:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enable RLS&lt;/strong&gt; on absolutely all tables (Authentication &amp;gt; Policies).&lt;/li&gt;
&lt;li&gt;Go to &lt;em&gt;Authentication &amp;gt; Providers &amp;gt; Email&lt;/em&gt; and toggle &lt;strong&gt;Confirm email&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Always use &lt;code&gt;auth.uid() = user_id&lt;/code&gt; in your rules; never trust IDs passed via the JSON body.&lt;/li&gt;
&lt;li&gt;Scan your application with &lt;strong&gt;&lt;a href="https://supasec.dev/" rel="noopener noreferrer"&gt;SupaSec&lt;/a&gt;&lt;/strong&gt; to ensure no sensitive data is leaking on your API's public layer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Remember: In Serverless and BaaS architectures, frontend convenience dictates the pace, but proper database configuration ensures the developer sleeps soundly at night.&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>security</category>
      <category>webdev</category>
      <category>lovable</category>
    </item>
  </channel>
</rss>
