TL;DR
Supabase itself is secure and SOC 2 certified, but many Supabase projects are vulnerable because of misconfiguration. The #1 issue is missing Row Level Security (RLS) policies. Without RLS, anyone with your public anon key can read and modify all your data. Supabase is safe when configured correctly, but the defaults don't protect you.
What is Supabase?
Supabase is an open-source Firebase alternative providing a PostgreSQL database, authentication, realtime subscriptions, storage, and edge functions. It's popular for full-stack apps and is the default backend for many AI app builders like Lovable and Bolt.
Our Verdict
What's Good
- PostgreSQL's mature security
- Built-in Row Level Security
- SOC 2 Type II certified
- Auth with JWT tokens
- Self-hosted option
What to Watch
- RLS disabled by default
- Public anon key exposed
- AI tools often skip RLS
- Complex policy writing
- Easy to misconfigure
The RLS Problem
Row Level Security (RLS) is Supabase's key security feature, but it's not enabled by default on new tables:
Critical: Without RLS enabled, anyone who knows your Supabase URL and anon key (which are public in your frontend) can read, modify, and delete all data in that table. This is the most common security issue we see in Supabase projects.
Why This Happens
- AI app builders often create tables without enabling RLS
- Quick prototypes skip security configuration
- Developers may not understand the anon key exposure
- Testing with RLS off and forgetting to enable it
How to Check
- Go to your Supabase dashboard
- Navigate to Database → Tables
- Check the shield icon next to each table
- If the shield has a warning, RLS is disabled
Common Supabase Vulnerabilities
| Issue | Risk | Fix |
|---|---|---|
| RLS not enabled | Critical | Enable RLS on all tables |
| Permissive RLS policies | High | Review and restrict policies |
| Service key in frontend | Critical | Only use in server-side code |
| Missing auth checks | High | Require auth in policies |
| Overly broad storage policies | Medium | Restrict bucket access |
Service Key vs Anon Key
Never expose the service_role key in frontend code. The anon key is meant to be public and works with RLS. The service key bypasses all security and should only be used server-side.
Supabase Auth Security
Supabase Auth is generally secure when used correctly:
- JWT tokens with short expiration
- Secure password hashing (bcrypt)
- Built-in MFA support
- OAuth provider integration
Common Auth Mistakes
- Not verifying email before allowing access
- Weak password requirements
- Missing rate limiting on auth endpoints
- Not using HTTPS for redirects
Security Checklist
Before Going Live
- Enable RLS on every table with data
- Write restrictive RLS policies (deny by default)
- Test policies from the browser (not admin)
- Verify service key is not in frontend code
- Configure storage bucket policies
- Enable email verification
- Set up rate limiting for functions
Is Supabase safe for production?
Yes, when properly configured. Supabase itself is SOC 2 certified and uses PostgreSQL's mature security model. The platform is safe; the risk is misconfiguration, especially missing RLS policies.
Why is my anon key public?
The anon key is designed to be public. It's meant for client-side use and works with RLS to control access. The key itself doesn't grant access to data; your RLS policies determine what's accessible.
Can I use Supabase without RLS?
For development, yes, but never for production with real user data. Without RLS, any authenticated user can access all data. Even for internal tools, RLS is recommended.
How do I write secure RLS policies?
Start with a deny-all approach and explicitly allow what's needed. The most common pattern is "users can only access their own data" using auth.uid() = user_id. Test policies by querying as a regular user, not admin.