Audit de Codebase Lovable : Problèmes de Sécurité, Lacunes RLS et Clés API Exposées

Un client nous a contactés le mois dernier avec une application générée par Lovable déjà en production avec des clients payants. Il voulait que nous ajoutions quelques fonctionnalités et que nous « nettoyions un peu les choses ». Ce que nous avons trouvé lors de notre audit initial de codebase était... révélateur. Des clés API exposées dans le code côté client. Des politiques Row Level Security manquantes sur les tables contenant les données utilisateur. Des appels Supabase directs sans validation côté serveur. Et ce n'était pas un cas isolé -- nous avons maintenant audité six projets Lovable différents, et les modèles sont remarquablement cohérents.

Soyons clairs : Lovable est un outil impressionnant pour le prototypage. La vitesse à laquelle il génère une UI fonctionnelle à partir d'invites en langage naturel est véritablement remarquable. Mais il existe un énorme fossé entre « prototype fonctionnel » et « application prête pour la production », et ce fossé est rempli de vulnérabilités de sécurité que la plupart des fondateurs non techniques ne savent même pas chercher.

Cet article est une analyse technique de ce que nous avons trouvé lors de plusieurs audits de codebase Lovable. Si vous avez créé quelque chose avec Lovable et que vous recevez de l'argent réel ou des données d'utilisateurs, vous devez lire ceci.

Table des matières

Audit de Codebase Lovable : Problèmes de Sécurité, Lacunes RLS et Clés API Exposées

Ce que Lovable génère réellement

Lovable génère des applications React (généralement avec Vite) avec Tailwind CSS et des composants shadcn/ui, connectées à un backend Supabase. La pile elle-même est solide -- nous construisons régulièrement avec ces mêmes outils dans notre travail de développement Next.js. Le problème n'est pas le choix des technologies. C'est la façon dont elles sont interconnectées.

Voici une structure de projet Lovable typique :

src/
├── components/
│   ├── ui/           # composants shadcn
│   ├── Dashboard.tsx
│   ├── Settings.tsx
│   └── ...
├── integrations/
│   └── supabase/
│       ├── client.ts  # ← C'est là que les problèmes commencent
│       └── types.ts
├── pages/
├── hooks/
└── lib/

Le code généré est propre et lisible. Je dois donner crédit à Lovable pour cela. Mais la lisibilité n'égale pas la sécurité. L'architecture prend des décisions qui sont acceptables pour une démo mais dangereuses pour la production.

Soyons précis.

Le Problème de la Clé API

Chaque projet Lovable que nous avons audité contient les identifiants Supabase dans le code côté client. Maintenant, avant que les défenseurs de Supabase ne se manifestent : oui, la clé anon est conçue pour être publique. La documentation de Supabase l'énonce explicitement. La clé anon est destinée à être utilisée dans le code côté client, et la sécurité est censée être appliquée par les politiques Row Level Security.

Mais c'est là que ça devient laid.

Dans trois des six projets que nous avons audités, nous avons trouvé la clé Supabase service_role soit :

  1. Codée en dur directement dans un fichier utilitaire
  2. Stockée dans un fichier .env qui a été committée dans le repo GitHub
  3. Référencée dans une Supabase Edge Function accessible sans authentification

La clé service_role contourne toutes les politiques RLS. Si quelqu'un la récupère, il a un accès complet en lecture/écriture à l'ensemble de votre base de données. Chaque table. Chaque ligne. Les données de chaque utilisateur.

// Modèle réel que nous avons trouvé dans un projet Lovable (clés masquées)
import { createClient } from '@supabase/supabase-js'

// Ceci était dans un fichier appelé lib/admin.ts
// importé et utilisé dans un composant côté client
const supabaseAdmin = createClient(
  'https://xxxxx.supabase.co',
  'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' // clé service_role !
)

Ceci n'a pas été généré directement par Lovable -- c'a été ajouté par le fondateur quand il avait besoin de fonctionnalités admin et a demandé à Lovable « ajouter un panneau admin ». Lovable a accepté, et comme il n'a pas de concept de limites de sécurité côté serveur vs côté client, il a mis la clé où c'était pratique.

Même lorsque seule la clé anon est exposée (comme prévu), le modèle de sécurité s'effondre si RLS n'est pas configuré correctement. Ce qui nous amène au grand problème.

Row Level Security : Le Tueur Silencieux

Row Level Security (RLS) est le mécanisme de sécurité principal de Supabase pour protéger les données au niveau de la base de données. Lorsqu'elle est configurée correctement, elle garantit que les utilisateurs ne peuvent accéder qu'à leurs propres données, quel que soit l'appel API effectué depuis le client.

Quand nous avons audité les six projets Lovable, voici ce que nous avons trouvé :

Projet Tables Totales Tables avec RLS Activé Tables avec Politiques RLS Correctes Données Sensibles Exposées
Tableau de bord SaaS 14 6 3 PII utilisateur, données de facturation
Application E-commerce 22 10 4 Historique de commandes, adresses
Suivi Santé 11 4 2 Dossiers médicaux, médicaments
Gestionnaire de Projets 18 8 5 Données clients, documents
Plateforme de Réservation 16 7 3 Informations de contact, horaires
Outil CRM 20 9 4 Données clients, notes

Relisez ceci. Dans l'application de suivi santé -- qui stockait des informations réelles sur la santé et les médicaments -- seules 2 tables sur 11 avaient des politiques RLS correctes. Quelqu'un avec la clé anon (qui est publique, rappelez-vous) pourrait interroger les dossiers de santé de tous les utilisateurs.

Les défaillances RLS les plus courantes que nous voyons :

Politiques Manquantes Complètement

Lovable crée souvent des tables sans activer RLS du tout. Dans Supabase, RLS est désactivé par défaut sur les nouvelles tables, ce qui signifie que quiconque possédant la clé anon peut lire toutes les données.

-- Ce que nous trouvons souvent : RLS n'est même pas activé
CREATE TABLE public.user_profiles (
  id UUID REFERENCES auth.users,
  full_name TEXT,
  email TEXT,
  phone TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Pas de ALTER TABLE ... ENABLE ROW LEVEL SECURITY;
-- Aucune politique définie

Politiques Trop Permissives

Quand Lovable ajoute RLS, les politiques sont souvent trop larges :

-- Politique commune générée par Lovable
CREATE POLICY "Les utilisateurs peuvent voir tous les profils"
  ON public.user_profiles
  FOR SELECT
  USING (true);  -- Cela permet à TOUT utilisateur authentifié de lire TOUS les profils

La correction devrait être :

-- À quoi cela devrait ressembler
CREATE POLICY "Les utilisateurs peuvent voir leur propre profil"
  ON public.user_profiles
  FOR SELECT
  USING (auth.uid() = id);

Politiques DELETE et UPDATE Manquantes

Même quand les politiques SELECT sont correctes, les politiques INSERT/UPDATE/DELETE manquent souvent ou sont incorrectes. Nous avons trouvé des cas où n'importe quel utilisateur authentifié pouvait mettre à jour le profil de n'importe quel autre utilisateur.

Audit de Codebase Lovable : Problèmes de Sécurité, Lacunes RLS et Clés API Exposées - architecture

Lacunes en Authentification et Autorisation

Lovable gère l'authentification de base raisonnablement bien -- il configure Supabase Auth avec email/mot de passe ou connexions sociales, et les flux de connexion/inscription fonctionnent généralement. Mais l'authentification (qui êtes-vous ?) et l'autorisation (que pouvez-vous faire ?) sont des choses différentes.

La couche d'autorisation est presque toujours incomplète ou inexistante.

Considérez une application SaaS multi-locataires. Les utilisateurs appartiennent à des organisations. Ils ne doivent voir que les données de leur organisation. Ils pourraient avoir différents rôles (admin, membre, visualiseur). Lovable ne génère rien de tout cela.

Ce que nous trouvons typiquement :

// Récupération de données générée par Lovable
const { data: projects } = await supabase
  .from('projects')
  .select('*')
  // Pas de filtre pour organization_id
  // Pas de vérification du rôle ou des permissions de l'utilisateur

La correction nécessite des modifications à la fois au niveau de la base de données (RLS) et au niveau de l'application. Vous avez besoin d'une table memberships mappant les utilisateurs aux organisations avec des rôles, des politiques RLS qui vérifient l'adhésion, et du code applicatif qui filtre de manière appropriée.

C'est le type de travail architectural qui est difficile à ajouter après coup. Cela affecte chaque requête, chaque composant, chaque page. Si vous construisez un SaaS multi-locataires avec Lovable, c'est la chose qui vous mord le plus fort.

Exposition de la Logique Métier Côté Client

Parce que Lovable génère des applications React pures côté client, toute la logique métier vit dans le navigateur. Cela signifie :

  • Les calculs de tarification sont visibles et manipulables dans les DevTools du navigateur
  • Les drapeaux de fonctionnalités pour différents niveaux d'abonnement sont vérifiés côté client
  • Les codes de réduction et la logique de validation sont dans le bundle JavaScript
  • L'écrêtage de débit API n'existe pas (il n'y a pas de serveur pour l'appliquer)

Nous avons trouvé un SaaS généré par Lovable où la vérification du niveau de tarification était entièrement côté client :

// Trouvé dans un composant du projet Lovable
const canAccessFeature = (feature: string) => {
  const plan = user?.subscription?.plan
  if (plan === 'pro') return true
  if (plan === 'basic' && BASIC_FEATURES.includes(feature)) return true
  return false
}

Un utilisateur pourrait simplement modifier cette fonction dans la console du navigateur -- ou appeler directement l'API Supabase sans cette vérification -- et accéder aux fonctionnalités pro avec un plan basic. La base de données n'avait aucune politique appliquant l'accès basé sur le plan.

C'est un problème architectural fondamental. La logique métier a besoin d'un composant côté serveur. Qu'il s'agisse de routes API Next.js, de Supabase Edge Functions, ou d'un service backend séparé -- quelque chose doit valider les opérations où l'utilisateur ne peut pas y toucher.

C'est exactement pourquoi nous recommandons souvent des frameworks comme Next.js ou Astro pour les applications SaaS de production -- ils vous donnent le rendu côté serveur et les routes API dès le départ.

Supabase Edge Functions : Ce qui manque

Certains projets Lovable utilisent bien les Supabase Edge Functions pour certaines opérations -- généralement la gestion des webhooks Stripe ou l'envoi d'e-mails. Mais l'implémentation a souvent des problèmes :

  1. Pas de validation des entrées : Les Edge Functions acceptent et traitent quel que soit le JSON envoyé sans valider la forme, les types ou les contraintes.

  2. CORS configuré pour permettre toutes les origines :

// Modèle courant dans les Supabase Edge Functions générées par Lovable
const corsHeaders = {
  'Access-Control-Allow-Origin': '*',  // Permet à n'importe quel site web d'appeler ceci
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}
  1. Pas de vérification d'authentification : La fonction ne vérifie pas le jeton JWT, donc les utilisateurs non authentifiés peuvent l'appeler.

  2. Les signatures de webhook Stripe ne sont pas vérifiées : Dans deux projets, le gestionnaire de webhook Stripe ne vérifiait pas la signature du webhook, ce qui signifie que n'importe qui pouvait envoyer de faux événements de paiement au point de terminaison.

// Ce que nous avons trouvé -- pas de vérification de signature
Deno.serve(async (req) => {
  const body = await req.json()
  // Traite directement l'événement sans vérifier qu'il provenait de Stripe
  if (body.type === 'checkout.session.completed') {
    // Mettre à jour l'abonnement de l'utilisateur
    await supabaseAdmin.from('subscriptions').update({
      status: 'active',
      plan: 'pro'
    }).eq('user_id', body.data.object.metadata.user_id)
  }
})

Cela signifie qu'un attaquant pourrait envoyer une demande POST à l'URL du webhook avec un événement checkout.session.completed contrefait et mettre à niveau n'importe quel utilisateur vers un plan pro gratuitement.

Modèles de Vulnérabilité Courants que Nous Avons Trouvés

Voici un résumé des problèmes les plus courants classés par gravité et fréquence :

Vulnérabilité Gravité Fréquence (sur 6) Exploitabilité
RLS manquant sur les tables sensibles Critique 6/6 Facile -- il suffit d'interroger la table
Politiques RLS trop permissives Élevée 6/6 Facile avec la clé anon
Exposition de la clé service_role Critique 3/6 Trivial si trouvée
Pas de vérification du webhook Stripe Élevée 4/6 Moyen -- besoin de l'URL du point de terminaison
Autorisation côté client uniquement Élevée 6/6 Facile avec DevTools
Pas de validation des entrées sur les Edge Functions Moyen 5/6 Moyen
Caractère générique CORS sur les Edge Functions Moyen 5/6 Facile
Données sensibles dans localStorage Moyen 4/6 Accès physique ou XSS
Pas de limitation de débit Moyen 6/6 Trivial
Références d'objets directs non sécurisées Élevée 5/6 Facile -- changer l'ID dans l'URL

Comment Auditer Votre Propre Projet Lovable

Si vous avez créé quelque chose avec Lovable qui gère des données utilisateur réelles, voici comment vérifier ces problèmes vous-même.

Étape 1 : Vérifier Votre Statut RLS Supabase

Allez à votre tableau de bord Supabase → Éditeur de Table. Cliquez sur chaque table et vérifiez si RLS est activé. Puis allez à Authentification → Politiques et examinez chaque politique.

Ou exécutez cette requête dans l'Éditeur SQL :

SELECT
  schemaname,
  tablename,
  rowsecurity
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY tablename;

Si rowsecurity est false pour n'importe quelle table contenant les données utilisateur, c'est un problème critique.

Étape 2 : Rechercher les Clés Exposées

Dans votre codebase, recherchez :

grep -r "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" src/
grep -r "service_role" src/
grep -r "SUPABASE_SERVICE" src/

Le premier modèle correspond au début des clés JWT Supabase. Si vous trouvez la clé service_role n'importe où dans votre répertoire src/, c'est une vulnérabilité critique immédiate.

Étape 3 : Tester les Politiques RLS

Créez un deuxième compte utilisateur de test. Connectez-vous en tant qu'utilisateur deux et essayez d'accéder aux données de l'utilisateur un. Vérifiez l'onglet Réseau du navigateur -- recevez-vous des données que vous ne devriez pas avoir ?

Vous pouvez également tester directement avec curl :

curl 'https://YOUR_PROJECT.supabase.co/rest/v1/user_profiles?select=*' \
  -H "apikey: YOUR_ANON_KEY" \
  -H "Authorization: Bearer YOUR_ANON_KEY"

Si cela retourne tous les profils utilisateur sans authentification, RLS est cassé.

Étape 4 : Vérifier les Edge Functions

Examinez chaque Edge Function pour :

  • Vérification JWT
  • Validation des entrées
  • Configuration CORS
  • Vérification de la signature du webhook (pour les gestionnaires Stripe/paiement)

Étape 5 : Inspectez le Bundle Côté Client

Exécutez npm run build et inspectez la sortie. Recherchez dans le JavaScript construit les clés API, la logique métier et les données de tarification. Tout dans le bundle est visible pour les utilisateurs.

Quand Reconstruire vs Quand Remédier

C'est la question que chaque fondateur Lovable se pose une fois qu'il réalise que ces problèmes existent. La réponse dépend de plusieurs facteurs :

Remédier si :

  • Votre application a moins de 10 tables
  • Vous n'avez pas de modèle d'autorisation complexe (pas de multi-location, pas de rôles)
  • L'architecture centrale (modèle de données, structure des pages) est solide
  • Vous avez principalement besoin d'ajouter des politiques RLS et de déplacer une logique côté serveur

Reconstruire si :

  • Vous avez besoin d'une architecture multi-locataires avec rôles et permissions
  • Votre logique métier est complexe et entièrement côté client
  • Vous avez besoin du rendu côté serveur pour le SEO ou les performances
  • Le schéma Supabase a des problèmes structurels importants
  • Vous êtes à une échelle où vous avez besoin d'une infrastructure appropriée

Pour la remédiation, vous regardez généralement l'ajout de politiques RLS sur toutes les tables, la migration de la logique sensible vers Edge Functions ou une couche côté serveur, l'implémentation d'une validation d'entrée appropriée et l'ajout de limitation de débit. C'est un projet de 2 à 4 semaines pour un développeur expérimenté en fonction de la complexité.

Pour une reconstruction complète, nous recommandons généralement une architecture découplée avec une séparation appropriée des préoccupations. Cela coûte plus cher au départ mais vous donne une base qui évolue. Consultez notre page de tarification pour avoir une idée de ce que cela ressemble.

Si vous n'êtes pas sûr du chemin qui vous convient, nous serions heureux de faire une évaluation rapide. Contactez-nous sur notre page de contact.

FAQ

Est-il sûr d'utiliser Lovable pour les applications de production ? Lovable peut générer un bon point de départ, mais la sortie a besoin d'un durcissement de sécurité important avant d'être prête pour la production. Le code généré manque des politiques RLS appropriées, de la validation côté serveur et de la logique d'autorisation. Pensez-y comme un échafaudage, pas la construction finie. Vous avez absolument besoin d'un développeur pour examiner et sécuriser le code avant que les utilisateurs réels lui confient leurs données.

Lovable expose-t-il mes clés API Supabase ? La clé Supabase anon est intentionnellement publique -- c'est par conception, et le modèle de sécurité de Supabase en tient compte grâce à RLS. Le problème est quand Lovable (ou vous, via les invites) place la clé service_role dans le code côté client. La clé anon étant publique n'est sûre que si vos politiques RLS sont impeccables, ce qui dans les projets Lovable générés, elles ne le sont généralement pas.

Qu'est-ce que Row Level Security et pourquoi est-ce important ? Row Level Security (RLS) est une fonctionnalité PostgreSQL que Supabase utilise pour contrôler quelles lignes un utilisateur peut lire, insérer, mettre à jour ou supprimer. Sans RLS, quiconque possédant votre clé anon publique peut interroger votre base de données entière -- les données de chaque utilisateur, chaque enregistrement privé. C'est le mécanisme de sécurité unique le plus important dans une application basée sur Supabase, et c'est la chose unique la plus mal configurée dans les projets Lovable.

Puis-je corriger les problèmes de sécurité de Lovable moi-même sans développeur ? Si vous comprenez SQL et la syntaxe de politique RLS de Supabase, vous pouvez ajouter des politiques RLS basiques vous-même en utilisant le tableau de bord Supabase. Cependant, bien faire les politiques -- en particulier pour les scénarios complexes comme la multi-location, les ressources partagées ou l'accès administrateur -- nécessite de l'expérience. Une politique incorrecte peut soit verrouiller les utilisateurs de leurs propres données, soit laisser tout exposé. Pour n'importe quoi au-delà d'un simple projet personnel, obtenez des yeux professionnels.

Comment puis-je vérifier si la base de données de mon application Lovable est sécurisée ? Le test le plus rapide : ouvrez les DevTools de votre navigateur, allez à l'onglet Réseau, et regardez les appels API Supabase que votre application effectue. Copiez la valeur de l'en-tête apikey. Puis utilisez curl ou Postman pour interroger directement vos tables en utilisant juste cette clé sans jeton d'authentification. Si vous recevez les données d'autres utilisateurs -- ou n'importe quelles données du tout sur les tables qui devraient être privées -- votre RLS est cassé.

Quels sont les plus grands risques de sécurité avec le code généré par l'IA en général ? Les générateurs de code IA optimisent pour faire fonctionner les choses, pas pour les sécuriser. Ils n'ont pas un modèle mental de votre paysage de menaces. Les plus grands risques sont : secrets exposés, validation d'entrée manquante, contrôles d'accès trop permissifs, et l'absence de limites de sécurité côté serveur. Ce ne sont pas uniques à Lovable -- des problèmes similaires existent dans le code de Cursor, v0, Bolt et d'autres outils IA. La différence est que Lovable génère des applications complètes que les gens déploient directement en production.

Devrais-je passer de Supabase à un backend différent après avoir utilisé Lovable ? Supabase lui-même va bien. C'est une plateforme solide avec des capacités de sécurité appropriées. Le problème est la façon dont Lovable la configure. Vous n'avez pas besoin d'abandonner Supabase -- vous devez configurer correctement les politiques RLS, déplacer les opérations sensibles vers Edge Functions, et ajouter la couche d'autorisation que Lovable a ignorée. L'infrastructure est bonne ; la configuration a juste besoin de travail.

Combien cela coûte-t-il de corriger les problèmes de sécurité dans une application générée par Lovable ? Pour une remédiation simple -- ajout de politiques RLS, sécurisation des Edge Functions, suppression des clés exposées, ajout d'une validation d'entrée basique -- vous regardez environ $3 000-$8 000 en fonction du nombre de tables et de la complexité de votre modèle d'autorisation. Une reconstruction complète avec une architecture appropriée coûte $15 000-$50 000 + selon la portée. Le chemin de remédiation est presque toujours plus rentable si votre modèle de données central est solide.