Lovable : les 5 failles de sécurité que ton app générée oublie


Sommaire
- Pourquoi ton app Lovable démarre avec ces failles
- 1. La clé service_role qui finit dans le navigateur
- 2. Le RLS désactivé : toute la base est ouverte
- 3. Les buckets de stockage publics
- 4. L'authentification trop ouverte
- 5. Les edge functions et routes API sans vérification
- Lovable fait déjà une partie du boulot
- Vérifie ton app en 5 minutes
- Questions fréquentes
- Lovable gère-t-il la sécurité automatiquement ?
- La clé anon (publishable) peut-elle rester dans le frontend ?
- Pourquoi Supabase laisse-t-il les tables ouvertes par défaut ?
- Comment savoir si mon RLS est bien configuré ?
- Lovable ou Bolt : lequel est le plus sûr ?
- Sources
Les cinq failles de sécurité les plus courantes sur une app Lovable sont : la clé service_role exposée dans le navigateur, le RLS désactivé, les buckets de stockage publics, l'authentification trop ouverte et les edge functions sans contrôle de session ni rate limiting. Chacune se corrige en collant un prompt précis dans Lovable, et un scan de sécurité suffit à les détecter.
Lovable te génère une app en quelques minutes et la branche, par défaut, sur une base Supabase. Le souci : cette base arrive avec des réglages permissifs, et l'agent d'IA ne les verrouille pas tout seul. Voici comment repérer et fermer les cinq failles, une par une.
Pourquoi ton app Lovable démarre avec ces failles
Lovable ne crée pas une app « non sécurisée » : il crée une app rapide. Pour que le premier écran s'affiche sans friction, la base Supabase est livrée avec des valeurs par défaut pensées pour le développement, pas pour la production.
La documentation Supabase est explicite : une table sans Row Level Security est lisible et modifiable par tout rôle qui a un droit dessus, et sur les projets existants une nouvelle table démarre avec des droits déjà larges. L'IA qui génère ton code suit le chemin le plus simple : elle lit, elle écrit, elle expose ce qui fonctionne. Elle n'active pas la sécurité parce que personne ne le lui a demandé. C'est exactement le rôle de la checklist qui suit.
1. La clé service_role qui finit dans le navigateur
Supabase fournit deux types de clés. La clé publishable (l'ancienne anon) peut rester dans le navigateur : elle est faite pour ça, et elle n'atteint que ce que le RLS autorise. La clé secret (l'ancienne service_role) est le passe-partout : elle contourne toutes tes policies RLS et donne accès à toute la base. Elle ne doit jamais quitter ton serveur.
C'est la faille la plus fréquente sur les apps Lovable. Pendant le développement, l'agent colle parfois la service_role directement dans un appel côté navigateur parce que « ça marche » quand une requête échoue à cause du RLS. Il la laisse, et n'importe qui ouvre la console, récupère la clé, et lit toute ta base : utilisateurs, commandes, messages.

Si tu veux la règle complète sur ce qui peut être exposé, on a un guide dédié : Clé anon vs service_role Supabase : laquelle exposer ?.
Comment vérifier : ouvre les DevTools de ton navigateur, onglet Network, et regarde si une clé service_role ou sb_secret_ apparaît dans une requête. Ensuite, colle ce prompt dans Lovable :
Dans tout le projet, cherche chaque appel qui initialise Supabase ou passe une clé.
Règle à appliquer :
- côté navigateur (tout fichier servi au client), n'utilise QUE la clé publishable (sb_publishable_... ou l'ancienne anon).
- la clé secret (sb_secret_...) ou service_role ne doit apparaître QUE dans une Edge Function ou un code serveur, jamais dans un fichier qui part au navigateur.
Remplace toute occurrence de service_role / sb_secret_ dans le frontend par la clé publishable, puis déplace la logique serveur vers une Edge Function si nécessaire.
Vérifie ensuite que plus aucun fichier du frontend ne contient "service_role" ni "sb_secret", et que l'onglet Network ne renvoie plus cette clé au navigateur.
À noter : la clé publishable n'est pas un secret, mais elle n'est pas une protection à elle seule. C'est le RLS qui décide de ce qu'elle peut lire. Si le RLS est désactivé, la clé publishable suffit à tout lire. C'est la faille suivante.
2. Le RLS désactivé : toute la base est ouverte
Le Row Level Security (RLS) est la règle qui décide, ligne par ligne, qui peut lire ou écrire quelle donnée dans ta base. Sans lui, toute personne qui a la clé publishable — c'est-à-dire n'importe qui qui ouvre ton site — peut lire et écrire dans tes tables.
Sur Supabase, une table du schéma public sans RLS est lisible et modifiable par tout rôle qui a un droit dessus. Et une nouvelle table démarre avec des droits déjà accordés aux rôles anon et authenticated. Ajouter une policy ne retire pas ces droits : il faut aussi les révoquer. C'est le piège typique d'une app Lovable : tu demandes « crée une table pour les utilisateurs », l'agent la crée, et elle reste ouverte. Un visiteur non connecté peut alors lire tous les comptes, voire en modifier.

On a couvert le sujet en profondeur dans Supabase RLS : sécuriser ton app codée avec l'IA.
Comment vérifier : essaie d'appeler ton API Supabase avec la clé publishable, sans être connecté. Si tu reçois des données, le RLS n'est pas en place. Ensuite, colle ce prompt :
Pour chaque table du schéma public :
1. Active le Row Level Security : ALTER TABLE <table> ENABLE ROW LEVEL SECURITY;
2. Révoque les droits par défaut des rôles anon et authenticated quand l'app n'en a pas besoin.
3. Ajoute des policies explicites : qui peut faire SELECT, INSERT, UPDATE, DELETE, et sur quelles lignes (ex. WHERE user_id = auth.uid()).
Vérifie ensuite, avec le rôle anon (non connecté), que tu ne peux plus lire ni écrire dans les tables protégées, et qu'un utilisateur connecté ne voit que ses propres lignes.
3. Les buckets de stockage publics
Supabase Storage stocke tes fichiers : avatars, factures, pièces d'identité, exports. Un bucket peut être public ou privé. Un bucket public signifie que n'importe qui connaissant l'URL peut télécharger le fichier, sans authentification.
L'agent Lovable choisit souvent « public » par défaut, parce que c'est le plus simple pour afficher une image. Si tu y ranges ensuite un document sensible — une facture, un justificatif, un export client — il fuit dès que l'URL circule.
Comment vérifier : dans Supabase Dashboard > Storage, regarde la colonne Public/Private de chaque bucket. Puis colle ce prompt :
Pour chaque bucket Supabase :
- passe les buckets qui contiennent des fichiers privés en "private" (pas "public").
- pour servir un fichier, utilise une URL signée (createSignedUrl) délivrée par une Edge Function qui vérifie que l'utilisateur connecté a le droit de voir ce fichier.
Vérifie ensuite qu'un fichier uploadé par un utilisateur n'est plus téléchargeable par une simple URL, sans être connecté.
4. L'authentification trop ouverte
Deux réglages de Supabase Auth font souvent du mal ensemble : « autoriser les nouvelles inscriptions » est activé, et la confirmation d'e-mail est désactivée. Concrètement, n'importe qui peut créer un compte en deux secondes, sans vérifier d'adresse e-mail.
Si en plus ton RLS est permissif (faille 2), un inconnu crée un compte et lit tout ce qu'un utilisateur authentifié peut lire. Ce n'est pas une vulnérabilité magique : c'est l'accumulation de deux réglages trop ouverts.
Comment vérifier : Supabase Dashboard > Authentication > Providers > Email. Puis colle ce prompt :
Dans Supabase Dashboard > Authentication > Providers > Email :
- si ton app ne propose pas d'inscription libre, désactive "Allow new users to sign up".
- active "Confirm email" pour que chaque compte soit validé par e-mail.
- ne garde que les providers que tu utilises réellement (désactive les autres).
Vérifie ensuite qu'un inconnu ne peut plus créer un compte et accéder aux données en quelques secondes.
5. Les edge functions et routes API sans vérification
Lovable peut te générer des Edge Functions (Supabase) ou des routes API. Trois erreurs y reviennent :
- Pas de contrôle de session. La fonction exécute la requête sans vérifier qui l'appelle. N'importe qui peut l'appeler directement.
- Trop de données renvoyées. La fonction fait un
SELECT *et renvoie tout, y compris les données des autres utilisateurs. C'est le mécanisme de l'IDOR : tu changes uniddans l'URL, et tu reçois les données de quelqu'un d'autre. - Pas de rate limiting. Un endpoint qui appelle une IA ou un paiement peut être appelé des milliers de fois si rien ne le limite, et la facture suit.
Comment vérifier : appelle ton endpoint sans jeton de session, puis avec l'id d'une donnée qui n'est pas la tienne. Si tu reçois des données, il y a un problème. Colle ensuite ce prompt :
Dans chaque Edge Function ou route API :
1. Vérifie la session : récupère le jeton d'accès de l'appelant et valide-le (getUser) avant toute lecture ou écriture.
2. Vérifie la propriété : avant de renvoyer ou modifier une donnée, confirme qu'elle appartient à l'utilisateur connecté. Ne renvoie jamais un SELECT * tel quel.
3. Ajoute un rate limiting sur les endpoints coûteux ou sensibles.
Vérifie ensuite qu'un appel sans session renvoie une erreur 401, et qu'un utilisateur ne peut pas lire les données d'un autre en changeant un id.
Lovable fait déjà une partie du boulot
Avant de conclure que tout est à faire à la main : Lovable a intégré une analyse de sécurité automatique. À chaque publication, il lance un scan de base qui vérifie la configuration de ta base, tes règles RLS, les réglages du projet cloud et les schémas de mauvaise configuration connus, en 10 à 15 secondes. Une analyse approfondie à la demande prend environ 3 minutes, et les administrateurs peuvent activer la correction automatique ou bloquer la publication en cas de problème critique.
C'est utile, mais c'est un filet de sécurité, pas une garantie. Le scan te signale ce qui cloche au moment de publier ; il ne décide pas à ta place de ce qui est public ou privé, ni de qui a le droit de lire quoi. La checklist ci-dessus reste la référence.
Vérifie ton app en 5 minutes
Si tu veux un premier état des lieux sans attendre, fais ces trois gestes :
- Ouvre l'onglet Network de ton navigateur et cherche
service_roleousb_secret_dans les requêtes. - Appelle ton API Supabase avec la clé publishable, sans être connecté : si des données reviennent, ton RLS est à revoir.
- Dans Supabase Storage, vérifie qu'aucun bucket public ne contient de fichier sensible.
Ces trois points couvrent les failles les plus graves et les plus fréquentes. Pour le reste — clés exposées dans le JavaScript, en-têtes, API qui renvoie trop — un scanner fait le tour en quelques minutes et te montre la preuve, requête par requête.
Questions fréquentes
Lovable gère-t-il la sécurité automatiquement ?
Partiellement. Lovable lance une analyse de sécurité de base à chaque publication (configuration de la base, RLS, réglages cloud) et propose une analyse approfondie à la demande. Mais il ne décide pas à ta place qui peut lire quoi : les réglages d'authentification, le RLS et les buckets restent de ta responsabilité.
La clé anon (publishable) peut-elle rester dans le frontend ?
Oui. Elle est conçue pour être exposée dans le navigateur et n'atteint que ce que tes policies RLS autorisent. Ce qui ne doit jamais apparaître côté client, c'est la clé service_role (ou la nouvelle clé secret), qui contourne le RLS.
Pourquoi Supabase laisse-t-il les tables ouvertes par défaut ?
Pour la vitesse de développement. Une table du schéma public sans RLS est lisible et modifiable par tout rôle qui a un droit dessus, et les nouvelles tables héritent de droits larges. Le verrouillage s'active explicitement, table par table.
Comment savoir si mon RLS est bien configuré ?
Le test le plus fiable : appelle ton API Supabase avec la clé publishable sans être connecté. Si tu reçois des données, c'est que le RLS est absent ou que les droits n'ont pas été révoqués. Ajouter une policy ne suffit pas : il faut aussi révoquer les droits par défaut.
Lovable ou Bolt : lequel est le plus sûr ?
La question n'est pas vraiment l'outil, mais les réglages de la base et du backend qu'il branche. Les failles décrites ici — RLS, clés, buckets, auth — se retrouvent sur toutes les apps générées, quel que soit le générateur. C'est la configuration que tu laisses ouverte qui fait la différence.
Quand tu as passé cette checklist, fais un dernier contrôle avec un scanner : Rustine regarde ton site comme le ferait un inconnu, te montre ce qui fuit avec la requête qui le prouve, et te donne le correctif à coller. Si tu travailles avec un agent, branche le serveur MCP de Rustine : il scanne et corrige lui-même, directement dans Lovable, Cursor ou Claude Code. Essayer Rustine