To secure a Cursor + Supabase + Vercel stack, you need to: (1) enable Row Level Security on all Supabase tables and write policies for each operation, (2) store your Supabase URL and anon key as NEXT_PUBLIC_ environment variables in Vercel while keeping the service_role key server-side only, (3) add security headers (X-Frame-Options, CSP) in vercel.json, (4) create a .cursorignore file to prevent AI from accessing your .env files, and (5) review all AI-generated code for missing authentication checks. This blueprint covers all three tools with color-coded guidance showing which security tasks belong to each platform.
TL;DR
This is the most popular vibe coding stack. Key security priorities: enable Row Level Security (RLS) on all Supabase tables, store your Supabase keys in Vercel environment variables, add security headers in vercel.json, and review AI-generated code for authentication gaps. About 73% of security issues in this stack come from missing RLS policies or exposed API keys.
Platform Guides & Checklists
Cursor Security Guide
Supabase Security Guide
Vercel Security Guide
Pre-Launch Checklist
Stack Overview
The Cursor + Supabase + Vercel stack has become the default choice for vibe coders building full-stack applications. Here's how the pieces fit together:
| Component | Role | Security Responsibility |
|---|---|---|
| Cursor | AI code editor | Code quality, secret detection in code |
| Supabase | Database + Auth + Storage | RLS policies, auth config, API key protection |
| Vercel | Hosting + Deployment | Environment variables, headers, edge functions |
Part 1: Supabase Security Configuration
Enable Row Level Security Supabase
RLS is the most critical security feature in Supabase. Without it, anyone with your anon key can read and modify all data.
-- Enable RLS
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
ALTER TABLE comments ENABLE ROW LEVEL SECURITY;
-- Example policy: users can only read their own data
CREATE POLICY "Users can view own data"
ON users FOR SELECT
USING (auth.uid() = id);
-- Example policy: users can only update their own data
CREATE POLICY "Users can update own data"
ON users FOR UPDATE
USING (auth.uid() = id);
Common mistake: Creating tables without RLS enabled. Cursor might generate table creation SQL without RLS. Always add ENABLE ROW LEVEL SECURITY immediately after creating any table.
Protect Your Supabase Keys Supabase Vercel
Supabase provides two types of keys:
| Key Type | Where to Use | Exposure Risk |
|---|---|---|
| anon/public key | Frontend (browser) | Safe if RLS is configured |
| service_role key | Server only | Never expose (bypasses RLS) |
# Public (can be exposed to browser)
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
# Private (server-side only)
SUPABASE_SERVICE_ROLE_KEY=eyJ...
Configure Auth Settings Supabase
In the Supabase dashboard, configure these auth settings:
- Site URL: Set to your production domain
- Redirect URLs: Add only your app's domains
- Email confirmations: Enable for production
- Password requirements: Set minimum length (8+ characters)
Part 2: Vercel Security Configuration
Set Security Headers Vercel
Add security headers to protect against common attacks:
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "Referrer-Policy",
"value": "strict-origin-when-cross-origin"
},
{
"key": "Permissions-Policy",
"value": "camera=(), microphone=(), geolocation=()"
}
]
}
]
}
Configure Environment Variables Vercel
In Vercel's dashboard, add your environment variables:
- Go to Project Settings > Environment Variables
- Add variables for each environment (Production, Preview, Development)
- Prefix client-side variables with
NEXT_PUBLIC_ - Keep service keys without the prefix (server-only)
Tip: Use different Supabase projects for development and production. This prevents accidental data exposure and makes it easier to test RLS policies.
Part 3: Cursor Security Practices
Configure .cursorignore Cursor
Prevent sensitive files from being sent to AI:
# Environment files
.env
.env.local
.env.production
# Supabase local config
supabase/.env
# Any credentials
**/credentials.json
**/service-account.json
Review AI-Generated Code Cursor
When Cursor generates code that interacts with Supabase, check for:
- Missing auth checks: Ensure protected routes verify the user session
- Direct service_role usage: Use anon key on client, service_role only on server
- Hardcoded keys: Replace any hardcoded values with environment variables
- Missing error handling: Don't expose error details to users
// Client-side (browser)
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
// Server-side (API routes, server components)
import { createClient } from '@supabase/supabase-js'
const supabaseAdmin = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
)
Security Checklist with Tool Attribution
Pre-Launch Checklist for Cursor + Supabase + Vercel
Common Vulnerabilities in This Stack
| Vulnerability | Cause | Fix |
|---|---|---|
| Data exposed to all users | RLS not enabled or no policies | Enable RLS, create policies |
| API key in git history | Committed .env file | Rotate key, add to .gitignore |
| Unauthorized data modification | Missing UPDATE/DELETE policies | Add policies for all operations |
| Service key exposed | Used service_role on client | Move to server-side only |
Alternative Stack Configurations
Cursor + Firebase + Vercel Swap Supabase for Firebase. Different security model with Firestore rules instead of RLS.
Cursor + Supabase + Netlify
Same database, different host. Netlify uses _headers file instead of vercel.json.
Bolt.new + Supabase + Vercel
Swap Cursor for Bolt.new. Same Supabase/Vercel config, different AI code review approach.
Is the Supabase anon key safe to expose?
Yes, if RLS is properly configured. The anon key is designed for client-side use and only allows access that your RLS policies permit. Think of it as a "public API key" that still requires authentication for protected data.
Do I need different Supabase projects for dev and production?
It's strongly recommended. Using separate projects prevents accidental data leaks, lets you test RLS changes safely, and gives you isolated environments for development.
How do I test if my RLS policies work?
Use the Supabase SQL editor with "Run as authenticated user" to test policies. Also test your app while logged out and as different users to verify data isolation.