Security Guide for Lovable and Bolt Apps
Why Lovable and Bolt Apps Need Extra Security Attention
Lovable and Bolt are the fastest ways to go from idea to deployed app. You describe what you want, and within minutes you have a working web application with a database, auth, and a UI.
The tradeoff is security. Both tools use Supabase as their default database and generate full-stack code that often has critical security gaps. Here's what we find when scanning Lovable and Bolt apps with VibeSafe.
The Top 3 Vulnerabilities
1. Supabase Service Role Key in Client Code
Severity: Critical
This is the #1 issue we find in Lovable and Bolt apps. The service_role key bypasses all Row Level Security. If it's in your client bundle, your entire database is exposed.
How to detect:
# Search your built output
grep -r "service_role" .next/static/ dist/ build/
Or run a VibeSafe scan — this is the first thing we check.
How to fix:
- Remove the service_role key from any file that runs in the browser
- Use only the anon key for client-side Supabase calls
- Move any server-only operations to API routes
- Rotate your service_role key in Supabase dashboard (Settings > API)
2. Missing Row Level Security Policies
Severity: Critical
Both Lovable and Bolt create Supabase tables but often skip RLS policies. Without RLS, anyone with the anon key can read and write all data.
How to check:
Go to your Supabase dashboard > Table Editor. If you see a yellow warning icon next to a table, RLS is disabled.
How to fix:
-- For every table in your database:
ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;
-- Then add appropriate policies. For example:
CREATE POLICY "Users read own data"
ON your_table FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY "Users insert own data"
ON your_table FOR INSERT
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users update own data"
ON your_table FOR UPDATE
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users delete own data"
ON your_table FOR DELETE
USING (auth.uid() = user_id);
3. No Security Headers
Severity: High
Neither Lovable nor Bolt add security headers to the generated application. This means no HSTS, no CSP, no X-Frame-Options.
How to fix:
If your app is a Next.js app (Lovable's default), add headers in next.config.ts:
async headers() {
return [{
source: "/(.*)",
headers: [
{ key: "X-Frame-Options", value: "DENY" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains; preload" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
],
}];
}
Lovable-Specific Issues
Direct Supabase Queries in Components
Lovable generates React components that query Supabase directly. This means RLS is your only line of defense — and if RLS is missing, everything is exposed.
Pattern to watch for:
// Lovable generates this in components
const { data } = await supabase
.from("profiles")
.select("*"); // Returns ALL profiles if RLS is off
Fix: Add RLS policies (see above) and limit queries to the current user's data.
Hardcoded Redirect URIs
Lovable sometimes hardcodes localhost:3000 as an OAuth redirect URI, which breaks auth in production or creates security holes.
Fix: Set redirect URIs in your Supabase dashboard (Authentication > URL Configuration) to only include your production domain.
Bolt-Specific Issues
API Keys in Generated Config Files
Bolt creates configuration files that sometimes include API keys in the frontend bundle.
Fix: Audit every .env variable. Anything that's a secret should not have NEXT_PUBLIC_, VITE_, or REACT_APP_ prefix.
Missing Error Handling Exposing Stack Traces
Bolt-generated API routes sometimes return raw error objects that include file paths and stack traces.
Fix: Catch errors and return generic error messages:
try {
// API logic
} catch (error) {
console.error(error); // Log server-side only
return Response.json(
{ error: "Something went wrong" },
{ status: 500 }
);
}
Quick Security Audit Checklist
- [ ] Supabase service_role key is server-only
- [ ] RLS is enabled on every table
- [ ] RLS policies exist for SELECT, INSERT, UPDATE, DELETE
- [ ] Security headers are configured
- [ ] No API keys in client-side code
- [ ] OAuth redirect URIs are set to production domain
- [ ] Error messages don't leak internal details
Automate It
Don't trust a manual checklist alone. Run a VibeSafe scan on your deployed URL after every major change. It catches the issues that are easy to miss, especially the ones AI tools create without you realizing.