Vulnerability
Supabase

API Key Exposure in Supabase Applications

Supabase has two main keys: the anon key (public, safe for frontend) and the service_role key (secret, bypasses RLS). The most critical vulnerability is exposing the service_role key in client code, which grants unrestricted database access. Understanding this distinction is essential for Supabase security.

Scan Your Supabase App

How API Key Exposure Manifests in Supabase

Key exposure in Supabase apps occurs when: The service_role key is used in frontend code, either directly or through environment variables prefixed with NEXT_PUBLIC_ or VITE_. This key bypasses all RLS policies. Developers confuse the anon key with the service_role key and try to "hide" the anon key unnecessarily, while leaving the service_role key improperly secured. Edge Functions or API routes log the service_role key in error messages or include it in client responses. The service_role key is committed to git repositories.

Real-World Impact

A developer used the service_role key in their Next.js frontend to "bypass RLS issues during development" and forgot to switch it back. The key was embedded in the production JavaScript bundle. An attacker extracted it, bypassed all RLS policies, and had full read/write access to every table in the database.

Step-by-Step Fix

1

Use anon key in frontend, service_role on server only

Separate client and server Supabase clients.

// lib/supabase-client.ts (for frontend)
import { createBrowserClient } from '@supabase/ssr';

export const supabase = createBrowserClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! // Public, safe
);

// lib/supabase-admin.ts (for server-side only)
import 'server-only';
import { createClient } from '@supabase/supabase-js';

export const supabaseAdmin = createClient(
  process.env.SUPABASE_URL!, // No NEXT_PUBLIC_ prefix
  process.env.SUPABASE_SERVICE_ROLE_KEY! // Secret, server only
);
2

Fix RLS instead of using service_role

If you need service_role to make queries work, your RLS policies need fixing.

-- If client queries fail, fix the RLS policy instead of using service_role
-- Common issue: missing policy for the operation

-- Add missing SELECT policy
CREATE POLICY "Users can view own records" ON "my_table"
  FOR SELECT TO authenticated
  USING ((select auth.uid()) = user_id);

-- Add missing INSERT policy with proper checks
CREATE POLICY "Users can insert own records" ON "my_table"
  FOR INSERT TO authenticated
  WITH CHECK ((select auth.uid()) = user_id);
3

Audit for exposed service_role key

Search your codebase for any client-side usage of the service_role key.

# Search for service_role in frontend-accessible code
grep -rn "service_role\|SERVICE_ROLE" --include="*.ts" --include="*.tsx" --include="*.js" src/
grep -rn "NEXT_PUBLIC.*SERVICE\|VITE.*SERVICE" .env*

# Check git history
git log -p --all | grep -i "service_role"

Prevention Best Practices

1. The anon key IS safe in frontend code - it is designed to be public. 2. The service_role key must ONLY be used in server-side code. 3. Never prefix service_role with NEXT_PUBLIC_ or VITE_. 4. Properly configure RLS so the anon key is sufficient for client operations. 5. Use Supabase Edge Functions for operations requiring elevated privileges.

How to Test

1. Search frontend bundle for the service_role key pattern (eyJ... JWT format). 2. Check .env files for NEXT_PUBLIC_*SERVICE_ROLE* patterns. 3. Verify RLS is enabled and working with just the anon key. 4. Test API endpoints to ensure they do not return the service_role key. 5. Use Vibe App Scanner to detect key exposure in your Supabase application.

Frequently Asked Questions

Is the Supabase anon key a secret?

No. The anon key is designed to be public and included in frontend code. It authenticates requests to PostgREST but does not bypass security. RLS policies control what data users can access. The anon key is equivalent to a Firebase API key.

What happens if the service_role key is exposed?

The service_role key bypasses all RLS policies, granting full read/write access to every table. An attacker with this key can read, modify, or delete any data in your database. Immediately rotate the key in Supabase dashboard if exposed.

How do I rotate Supabase keys?

Go to your Supabase project Settings > API to view and rotate keys. After rotation, update the key in all server-side environments. The anon key rarely needs rotation since it is public. The service_role key should be rotated immediately if exposed.

Is Your Supabase App Vulnerable to API Key Exposure?

VAS automatically scans for api key exposure vulnerabilities in Supabase applications and provides step-by-step remediation guidance with code examples.

Scans from $5, results in minutes. Get actionable fixes tailored to your Supabase stack.