SupabaseMedium

Public Table Read Access

Tables are readable by anonymous users through the Supabase API, potentially exposing sensitive data to unauthenticated visitors.

Last updated 2026-01-15

What Is This Vulnerability

Public table read access occurs when a table's RLS SELECT policy allows the anon (anonymous) role to read data. While RLS is enabled, the policy explicitly or implicitly grants read access to unauthenticated users. This can be intentional for public content (e.g., published blog posts), but is often a misconfiguration that exposes data meant only for authenticated users.

-- RLS is enabled, but the SELECT policy allows anonymous reads
CREATE POLICY "Public read"
  ON products FOR SELECT
  USING (true);  -- Both anon and authenticated roles can read

The distinction between this and "Missing RLS" is that RLS is enabled here, but the policies are configured to allow public access. The distinction from "RLS Bypass: Unauthorized SELECT" is that this specifically concerns anonymous (unauthenticated) access.

Why It's Dangerous

Even if the data seems non-sensitive, public read access can expose:

  • User-generated content that should require an account to view (gating content behind auth)
  • Metadata that reveals your application's structure, user count, or business metrics
  • Internal identifiers such as UUIDs, foreign keys, or references to other tables that aid further attacks
  • Scraped data that competitors or bad actors can harvest at scale
  • Pricing, inventory, or configuration data that gives competitors an advantage

Attackers commonly enumerate public tables first to understand the database schema, then pivot to more targeted attacks against tables with write vulnerabilities.

How to Detect

Test anonymous access by making API calls without an Authorization header (or with just the anon key):

curl 'https://YOUR_PROJECT.supabase.co/rest/v1/TABLE_NAME?select=*&limit=5' \
  -H "apikey: YOUR_ANON_KEY"

If data is returned, the table is publicly readable. You can also query RLS policies to find those that do not check for authentication:

SELECT tablename, policyname, roles, qual
FROM pg_policies
WHERE schemaname = 'public'
  AND cmd = 'SELECT'
  AND roles @> ARRAY['anon'];

AuditYourApp scans every table as an anonymous user and flags any that return data.

How to Fix

If the table should only be accessible to authenticated users, update the policy:

DROP POLICY "Public read" ON products;

-- Only authenticated users can read
CREATE POLICY "Authenticated users can read products"
  ON products FOR SELECT
  TO authenticated
  USING (true);

The TO authenticated clause restricts the policy to the authenticated role, excluding anonymous users. If only certain rows should be public, add a condition:

-- Only published products are publicly readable
CREATE POLICY "Public can view published products"
  ON products FOR SELECT
  USING (status = 'published' AND visibility = 'public');

-- Authenticated users can also see their own drafts
CREATE POLICY "Users can view own products"
  ON products FOR SELECT
  TO authenticated
  USING (auth.uid() = owner_id);

Review each table and determine the minimum access level required. Default to authenticated-only access and only open tables to anonymous users when there is a clear business requirement.

Scan your app for this vulnerability

AuditYourApp automatically detects security misconfigurations in Supabase and Firebase projects. Get actionable remediation in minutes.

Run Free Scan