← Back to blog
LOVABLE

Top 5 Security Vulnerabilities in Lovable-Built Apps

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.

Frequently asked questions

What security issues are most common in Lovable apps?

vibeAudit's April 2026 audit of 23 Lovable apps found 100% had Supabase RLS misconfigured, 60% leaked an API key in the client JS bundle, 56% had unauthenticated sensitive routes, and 100% shipped with no Content-Security-Policy. Lovable apps averaged 8 critical findings each.

Why are Lovable apps insecure by default?

Lovable generates functional UI fast but treats security as somebody else's problem. RLS is off by default on new Supabase tables, the anon key goes straight into the client bundle, and generated API routes ship without auth middleware. The feedback loop is visual — nothing warns the developer that 'works' and 'safe' are different.

How do I scan my Lovable app for security issues?

Paste your Lovable app URL into vibeAudit — free, 30 seconds, no signup. The scanner auto-detects Supabase, probes RLS on every public table, greps the JS bundle for leaked keys, and tests API routes for missing auth. It runs read-only, so your app is never modified.

What is the worst thing vibeAudit has found in a Lovable app?

A Lovable real-estate CRM shipped a Supabase JWT with role=service_role in its client bundle. That key bypasses every RLS policy on every table in the project — full read, full write, full delete on every bucket. Anyone who viewed the site source had god mode.

Can I fix Lovable's security issues without rewriting the app?

Yes. Most Lovable-specific vulnerabilities are one-line SQL or dashboard fixes: enable RLS on the table, add a policy, move secrets to server-side env vars, rotate the exposed anon key. vibeAudit's $4.99 deep scan returns copy-paste SQL and middleware code for every finding.

Does Lovable 2.0's built-in security scan find everything vibeAudit finds?

No. Lovable's scan checks whether RLS is enabled on a table; it does not verify the policies are correct. A table with USING(true) passes Lovable's check and fails vibeAudit's — because USING(true) means 'everyone can read every row'. vibeAudit tests policy correctness, not policy existence.

Is my Lovable app indexed by Google? Could an attacker find it?

Yes. Lovable subdomains are publicly crawlable and often land on Google within days of deployment. vibeAudit's research found dozens of Lovable apps in public showcase galleries with real users and paying customers — they are being found. Scan before you ship.

Is your app vulnerable?

Scan your app for free — read-only, no signup, ~30 seconds. vibeAudit runs the tests this post describes.

Scan your app free