La faille CVE-2025-48757 a un coupable unique, et il revient dans la quasi-totalité des fuites d'apps générées par IA : un RLS Supabase mal configuré. Pas absent par malveillance — juste insuffisant, parce que générer une app qui marche et générer une app qui protège ses données sont deux exercices différents.
Cet article est plus technique que les autres du dossier. Si vous (ou votre prestataire) avez les mains dans une app Supabase, voici exactement où ça casse et comment le corriger.
RLS, en une minute
Supabase expose votre base PostgreSQL directement au front-end via une API REST (PostgREST). La requête part du navigateur, avec une clé : la clé anon, qui est publique par conception (elle est dans le bundle JS).
Ce qui protège vos tables n'est donc pas la clé — c'est le RLS (Row Level Security). Le RLS, ce sont des politiques (policies) SQL qui décident, ligne par ligne, qui a le droit de lire ou écrire. Sans RLS restrictif, la clé anon suffit à tout lire.
Règle mentale : toute donnée accessible avec la clé anon doit être considérée comme publique. Tout le reste dépend de la qualité de vos policies.
Les 4 erreurs qui exposent vos données
1. Le RLS n'est pas activé du tout
Le cas le plus brutal. Une table sans ENABLE ROW LEVEL SECURITY est lisible par n'importe qui avec la clé anon. C'est exactement ce qui a exposé des milliers de lignes dans la faille publique.
-- À faire sur CHAQUE table contenant des données
ALTER TABLE public.users ENABLE ROW LEVEL SECURITY;
2. La policy "USING (true)" — la fausse sécurité
Activer le RLS ne suffit pas si la policy n'autorise tout le monde. C'est le piège que le scanner natif de Lovable ne détecte pas : il voit qu'une policy existe, pas qu'elle ne filtre rien.
-- DANGEREUX : autorise la lecture à tous, anon compris
CREATE POLICY "read" ON public.users FOR SELECT USING (true);
-- CORRECT : chaque utilisateur ne voit que ses lignes
CREATE POLICY "read own" ON public.users
FOR SELECT TO authenticated
USING (auth.uid() = user_id);
3. Le rôle anon oublié
Beaucoup de policies sont écrites pour authenticated mais laissent des droits au rôle anon par héritage ou par défaut. Vérifiez les GRANT et ciblez explicitement les rôles. Dans la plupart des apps, anon ne devrait avoir accès à presque rien.
4. Les fonctions SECURITY DEFINER avec search_path mutable
Une fonction SECURITY DEFINER s'exécute avec les droits de son créateur — elle contourne le RLS. Si son search_path n'est pas fixé, elle devient une porte dérobée exploitable.
-- Durcir chaque fonction SECURITY DEFINER
ALTER FUNCTION public.ma_fonction() SET search_path = '';
À cela s'ajoutent les RPC exécutables en anon et les buckets de stockage publics — autant de surfaces à vérifier.
Comment corriger, étape par étape
- Activer le RLS sur chaque table contenant des données.
- Réécrire les policies permissives : remplacer
USING (true)par des règles liées àauth.uid(). - Verrouiller le rôle anon : ne lui accorder que le strict nécessaire (souvent rien).
- Durcir les SECURITY DEFINER :
set search_path = ''+ droits d'exécution restreints. - Tester en anon : interroger l'API REST avec la seule clé anon, table par table. Toute table qui renvoie des lignes sans login est exposée.
L'étape 5 est la seule qui prouve quelque chose. C'est précisément ce que fait notre audit de sécurité, en lecture seule : un pré-scan instantané dans votre navigateur, ou un audit complet le jour même.
Pourquoi c'est si fréquent sur les apps générées par IA
Le générateur optimise pour le résultat visible : l'écran s'affiche, les données apparaissent. Que ces mêmes données soient aussi accessibles sans authentification ne se voit pas à l'usage — il faut explicitement aller interroger l'API en anon pour le constater. C'est un angle mort, pas une négligence : tant que personne ne regarde, tout semble fonctionner.
C'est aussi pour ça qu'aucun "score de sécurité" automatique de surface ne remplace une vraie vérification. Une policy qui existe n'est pas une policy qui protège.
FAQ — RLS Supabase
Faut-il activer le RLS sur absolument toutes les tables ?
Sur toutes les tables exposées via l'API (schéma public), oui. Une table sans RLS y est lisible avec la clé anon. Les tables internes non exposées peuvent suivre une autre logique, mais par défaut, RLS partout.
La clé service_role est-elle concernée ?
La clé service_role contourne le RLS — elle ne doit JAMAIS être exposée côté client, uniquement utilisée côté serveur (edge functions, backend). Si elle est dans votre bundle front, c'est une fuite critique à corriger immédiatement.
Comment tester mon RLS sans risque ?
En lecture seule : on interroge l'API REST avec la clé anon (publique) et on observe ce qui revient. Aucun écrit, aucune exploitation. C'est non destructif et c'est exactement ce que ferait un visiteur de votre site.
Le RLS suffit-il à être conforme RGPD ?
C'est une brique nécessaire mais pas suffisante. Le RGPD couvre aussi l'hébergement, la traçabilité des accès, la durée de conservation, le consentement. Le RLS verrouille l'accès aux données ; le reste relève de l'architecture et de la gouvernance.
Ce qu'on en retient
- La clé anon est publique : seul un RLS restrictif protège vos tables.
- Quatre pièges : RLS désactivé, policy
USING (true), rôle anon oublié, SECURITY DEFINER non durcie. - Une policy qui existe ≠ une policy qui protège — d'où l'angle mort des scores automatiques.
- Le seul test fiable : interroger l'API en anon, table par table.
Vous voulez savoir ce qui est exposé chez vous ? Lancez l'audit — en lecture seule, le jour même.