ScanVibeScanVibe
·7 min read·ScanVibe Team

How to Secure Your Supabase App in 10 Minutes

supabasesecurityguide

How to Secure Your Supabase App in 10 Minutes

Supabase is the go-to backend for vibe coders. Lovable, Bolt, and dozens of AI coding tools default to Supabase for auth, database, and storage. It's fast to set up, generous on the free tier, and pairs perfectly with frameworks like Next.js and React.

But there's a problem: most Supabase apps ship with critical security misconfigurations. We've scanned hundreds of production apps with ScanVibe, and the same issues come up again and again.

The good news? You can fix all of them in about 10 minutes. Here's how.

Time estimate: 10 minutes to go through this guide. 5 sections, each with a clear problem and a copy-paste fix.

1. Enable Row Level Security (RLS) on Every Table

78% of Supabase apps we scan have at least one table without RLS enabled

This is the #1 Supabase security issue we see. Without RLS, anyone with your anon key can read and write every row in your database.

The Problem

When you create a table in Supabase, RLS is disabled by default. That means your anon API key — which is embedded in your frontend JavaScript — gives full access to all data.

-- Check which tables have RLS disabled
SELECT schemaname, tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public';

The Fix

Enable RLS on every table, then add policies for what should be accessible:

-- Enable RLS
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;

-- Allow users to read their own profile
CREATE POLICY "Users can read own profile"
  ON public.profiles FOR SELECT
  USING (auth.uid() = id);

-- Allow users to update their own profile
CREATE POLICY "Users can update own profile"
  ON public.profiles FOR UPDATE
  USING (auth.uid() = id);
Rule of thumb: If a table has RLS disabled and it's not a purely public lookup table, it's a vulnerability.

Common Patterns

For tables that should be publicly readable but only editable by owners:

-- Anyone can read
CREATE POLICY "Public read" ON public.posts
  FOR SELECT USING (true);

-- Only the author can insert/update/delete
CREATE POLICY "Author can modify" ON public.posts
  FOR ALL USING (auth.uid() = author_id);

For private tables (e.g., user settings, payment info):

-- Only authenticated users can access their own rows
CREATE POLICY "Private access" ON public.user_settings
  FOR ALL USING (auth.uid() = user_id);

2. Stop Exposing Your Service Role Key

Your Supabase project has two keys:

anon Safe for browser. Limited by RLS policies.
service_role Bypasses ALL RLS. Never expose in frontend.

The Problem

We frequently find the service_role key in:

If someone gets your service role key, they have full admin access to your database. They can read, write, and delete anything.

The Fix

  1. Check your environment variables. The service role key should only be in server-side env vars (no NEXT_PUBLIC_ prefix in Next.js).
# WRONG — exposed to the browser
NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY=eyJhb...

# RIGHT — server-side only
SUPABASE_SERVICE_ROLE_KEY=eyJhb...
  1. Use the anon key in your frontend client:
// Frontend client — uses anon key
import { createClient } from '@supabase/supabase-js';

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
  1. Use the service role key only in server-side code (API routes, server actions):
// Server-side only — never import this in client code
import { createClient } from '@supabase/supabase-js';

const supabaseAdmin = createClient(
  process.env.SUPABASE_URL!,
  process.env.SUPABASE_SERVICE_ROLE_KEY!
);

3. Secure Your Storage Buckets

The Problem

Many apps create public buckets or have storage policies that allow anyone to upload or overwrite files. We've seen:

The Fix

-- Only allow users to access their own files
CREATE POLICY "Users access own files" ON storage.objects
  FOR ALL USING (
    bucket_id = 'avatars'
    AND auth.uid()::text = (storage.foldername(name))[1]
  );
Best practices for storage:
• Use user-specific folders: avatars/{user_id}/photo.jpg
• Set file size limits in your upload logic
• Validate file types server-side
• Use signed URLs for private files instead of making buckets public

4. Configure Auth Properly

Supabase Auth is solid out of the box, but there are common misconfigurations.

Disable Email Confirmations Carefully

If you disable email confirmations (common during development), remember to re-enable them before going to production. Without confirmation, anyone can create accounts with fake emails.

Restrict Redirect URLs

In your Supabase dashboard under Authentication > URL Configuration:

# Add only your production domain and localhost
https://yourdomain.com/**
http://localhost:3000/**
Don't use wildcards like https://* — this allows redirect attacks where an attacker can steal auth tokens by redirecting to their own domain.

Enable Rate Limiting

Supabase has built-in rate limiting for auth endpoints. Make sure it's enabled:


5. Audit Your Database Functions

If you use Supabase Edge Functions or database functions, they can bypass RLS if they use SECURITY DEFINER.

The Problem

-- This function runs with the creator's permissions, not the caller's
CREATE FUNCTION get_all_users()
RETURNS SETOF public.profiles
LANGUAGE sql
SECURITY DEFINER  -- Dangerous: bypasses RLS
AS $$
  SELECT * FROM public.profiles;
$$;

The Fix

Use SECURITY INVOKER unless you have a specific reason not to:

CREATE FUNCTION get_user_profile(user_id uuid)
RETURNS public.profiles
LANGUAGE sql
SECURITY INVOKER  -- Safe: respects RLS
AS $$
  SELECT * FROM public.profiles WHERE id = user_id;
$$;

If you must use SECURITY DEFINER, add explicit permission checks inside the function.


Quick Checklist

Run through this in 10 minutes:


Automate It with ScanVibe

Don't want to check all this manually every time you deploy? ScanVibe scans your Supabase app for all these issues automatically. We check:

RLS Row Level Security detection
Keys Exposed API keys in frontend
Auth Auth endpoint weaknesses
+5 More security categories

One scan. 30 seconds. All the issues found.


Further Reading

Related articles

Scan your app now

Check your AI-built app for security vulnerabilities in seconds. Free, no signup required.

Start Scanning