Lovable turns ideas into deployed apps in minutes. It also turns your database into a public spreadsheet — unless you fix five things. Speed kills security, and Lovable optimizes for speed.
We scan Lovable apps all day. The same five holes show up every time. Here they are — worst first, with fixes you can paste right in.
1. Supabase Row Level Security (RLS) Disabled
Severity: Critical (CVSS 9.1)
This is the number one issue we find. Lovable creates Supabase tables for you, but it often doesn't enable Row Level Security. Without RLS, anyone who knows your Supabase project URL and anon key -- both of which are public in your JavaScript bundle -- can read, modify, or delete every row in your database.
That means any visitor to your app can pull every user's email, profile data, and private content with a single API call.
The fix:
-- Enable RLS on every table Lovable created
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;
-- Add a policy so users can only read their own data
CREATE POLICY "Users read own data" ON profiles
FOR SELECT USING (auth.uid() = user_id);
-- Add a policy so users can only update their own data
CREATE POLICY "Users update own data" ON profiles
FOR UPDATE USING (auth.uid() = user_id);
Run this in your Supabase SQL Editor. Do it for every table that contains user data.
Don't want to check manually? vibeAudit checks RLS automatically — paste your URL, 30 seconds, free. (Detailed RLS guide here)
2. Exposed Supabase Anon Key in Client JavaScript
Severity: High (CVSS 7.5)
Lovable puts your Supabase URL and anon key directly in your client-side code. This is technically by design -- the anon key is meant to be public. But it becomes a critical issue when RLS is disabled (see vulnerability #1 above), because the anon key becomes a master key to your entire database.
Even with RLS enabled, an exposed anon key lets attackers call any Supabase Edge Function or access any table that has overly permissive policies.
The fix:
// 1. Enable RLS on all tables (see fix #1)
// 2. Restrict your anon key's permissions in Supabase Dashboard:
// Settings -> API -> Under "anon" key, review permissions
// 3. For sensitive operations, use a server-side route:
// Instead of calling Supabase directly from the client:
const { data } = await supabase.from('admin_data').select('*')
// Call your own API route that uses the service_role key server-side:
const res = await fetch('/api/admin-data', {
headers: { Authorization: `Bearer ${session.access_token}` }
})
3. Missing Authentication on API Routes
Severity: High (CVSS 8.2)
Lovable generates API endpoints that often lack authentication middleware. We frequently find routes like /api/users, /api/settings, or /api/admin that return sensitive data to anyone who hits the URL -- no login required.
The fix:
// Add auth middleware to every sensitive API route
import { createClient } from '@supabase/supabase-js'
export async function GET(request: Request) {
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
// Verify the user is authenticated
const authHeader = request.headers.get('Authorization')
const { data: { user }, error } = await supabase.auth.getUser(
authHeader?.replace('Bearer ', '')
)
if (error || !user) {
return new Response('Unauthorized', { status: 401 })
}
// Now safe to return user-specific data
const { data } = await supabase
.from('profiles')
.select('*')
.eq('user_id', user.id)
return Response.json(data)
}
4. Environment Variables Committed to Git
Severity: High (CVSS 7.8)
When Lovable generates your project and you push it to GitHub, the .env file sometimes ends up in the repository. This exposes your Supabase service role key, Stripe secret key, and any other secrets you've configured. Even if you delete the file later, it remains in your Git history.
The fix:
# 1. Add .env to .gitignore immediately
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
# 2. Remove .env from Git history (if already committed)
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch .env" \
--prune-empty --tag-name-filter cat -- --all
# 3. Rotate ALL secrets that were exposed:
# - Supabase: Settings -> API -> Regenerate keys
# - Stripe: Dashboard -> Developers -> Roll API keys
# - Any other API keys in your .env file
# 4. Use your hosting platform's env vars instead
# Vercel: Settings -> Environment Variables
# Netlify: Site settings -> Environment variables
5. No Content Security Policy (CSP) Headers
Severity: Medium (CVSS 6.1)
Lovable apps rarely ship with security headers. Without a Content Security Policy, your app is more vulnerable to cross-site scripting (XSS) attacks. An attacker who finds an XSS vector can load external scripts, exfiltrate data, and hijack user sessions.
The fix:
// next.config.js — add security headers
const securityHeaders = [
{
key: 'Content-Security-Policy',
value: "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://*.supabase.co"
},
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
]
module.exports = {
async headers() {
return [{ source: '/(.*)', headers: securityHeaders }]
},
}
FAQ
Q: Is Lovable secure by default?
No. Lovable often creates Supabase tables without enabling Row Level Security, leaving your database publicly readable.
Q: How do I check if my Lovable app is vulnerable?
Run SELECT tablename, rowsecurity FROM pg_tables WHERE schemaname='public' in your Supabase SQL Editor. Any row showing false means that table is exposed.
Q: Does Lovable fix security issues automatically?
Lovable 2.0 added a basic security scan, but it only checks if RLS exists, not if it's configured correctly.
Built with Lovable? Paste your URL into vibeAudit. We'll tell you which of these five issues you have — in under a minute, free. Read-only scan, your app is never modified.