FixVibe

// docs / baas security / supabase service role exposure

Clé de rôle de service Supabase exposée en JavaScript : ce que cela signifie et comment la trouver

La clé de rôle de service Supabase est la clé maîtresse de votre base de données. Quiconque la détient contourne la sécurité au niveau des lignes, peut lire chaque colonne de chaque table et peut écrire ou supprimer ce qu'il veut. Elle est conçue pour vivre exclusivement dans le code côté serveur — jamais dans le navigateur. Lorsqu'un outil de codage IA la livre dans le bundle JavaScript, votre base de données est, en effet, publique. Cet article explique la forme du JWT qui identifie une clé fuitée, les trois motifs d'outils IA qui produisent la fuite, ce qu'il faut faire dans la première heure après détection, et comment scanner automatiquement avant les utilisateurs.

Qu'est-ce que la clé de rôle de service

Supabase délivre deux clés distinctes pour chaque projet : la clé anon (également appelée clé publiable dans les projets plus récents) et la clé service_role. Les deux sont des JSON Web Tokens signés par le secret JWT de votre projet. La différence est le claim role intégré dans le payload du JWT — anon pour la clé publique, service_role pour la clé maîtresse. PostgREST, Supabase Storage et Supabase Auth basculent tous en mode tout-contourner lorsqu'ils voient le claim service_role.

Décodez n'importe quelle clé Supabase sur jwt.io et regardez le payload. La forme d'un JWT de rôle de service est sans équivoque :

Payload décodé d'un JWT de rôle de service (affiché comme bloc mis en évidence ci-dessous).

json
{
  "iss": "supabase",
  "ref": "[project-ref]",
  "role": "service_role",
  "iat": 1700000000,
  "exp": 2000000000
}

Les projets Supabase plus récents délivrent des clés de type secret avec le préfixe sb_secret_ au lieu d'un JWT. Le comportement est identique — tout ce qui porte sb_secret_ dans un bundle public est tout aussi catastrophique.

Comment les outils de codage IA fuitent la clé de rôle de service

Nous avons vu les mêmes trois motifs dans des milliers d'applications vibe-codées. Chacun commence par un développeur demandant de l'aide à un outil IA et finit avec la clé de service intégrée dans un bundle.

Motif 1 : fichier .env unique avec préfixe NEXT_PUBLIC_

Le développeur demande à l'outil IA de « configurer Supabase » et accepte un unique .env avec les deux clés. L'outil IA — entraîné sur un corpus où la plupart des variables d'environnement sont exposées via NEXT_PUBLIC_* — préfixe les deux avec NEXT_PUBLIC_. Next.js intègre tout ce qui correspond à ce préfixe dans le bundle client au moment du build. Déployez sur Vercel, et la clé de service se trouve dans main.[hash].js.

Motif 2 : mauvaise clé dans l'appel createClient

Le développeur colle les deux clés dans un fichier config.ts généré par l'IA, et l'IA remplit par erreur l'appel createClient() côté navigateur avec process.env.SUPABASE_SERVICE_ROLE_KEY. Le build tire la variable, et le JWT atterrit dans le bundle.

Motif 3 : clé de rôle de service codée en dur dans les scripts de seed

Le développeur demande à l'outil IA d'écrire un script qui peuple la base de données. L'IA code en dur la clé de rôle de service directement dans le fichier (au lieu de la lire depuis l'environnement), commit le fichier dans le dépôt, et le repo public GitHub ou la route /scripts/seed.js de l'application déployée sert désormais la clé.

Comment le scan de bundle FixVibe détecte la fuite

Le check secrets-de-bundle de FixVibe télécharge chaque fichier JavaScript référencé par l'application déployée — chunks d'entrée, chunks chargés à la demande, web workers, service workers — et les passe à travers un détecteur qui décode tout ce qui correspond à la forme JWT (eyJ[base64-header].eyJ[base64-payload].[signature]). Si le payload décodé contient "role": "service_role", le scan le signale comme résultat critique avec le chemin du fichier et la ligne exacte où apparaît la clé. Le même check correspond également au motif plus récent sb_secret_* par préfixe.

Le scan ne s'authentifie jamais avec la clé découverte. Il identifie la forme et signale la fuite — utiliser la clé pour prouver l'exploitabilité serait un accès non autorisé à votre base de données. La preuve est dans le payload JWT lui-même.

Détectée — que faire dans la première heure

Une clé de rôle de service fuitée est une urgence en production. Supposez que la clé a été récoltée — les attaquants surveillent les bundles publics en temps réel. Traitez la base de données comme compromise jusqu'à ce que vous ayez fait tourner la clé et audité l'activité récente.

  1. Faites tourner la clé immédiatement. Dans le tableau de bord Supabase, allez dans Paramètres du projet → API → Clé de rôle de service → Réinitialiser. L'ancienne clé est invalidée en quelques secondes. Tout code côté serveur utilisant la clé doit être mis à jour et redéployé avant que la rotation ne prenne effet.
  2. Auditez l'activité récente de la base de données. Ouvrez Database → Logs dans le tableau de bord. Filtrez sur les 7 derniers jours. Recherchez des requêtes SELECT * inhabituelles contre des tables avec PII, des instructions UPDATE ou DELETE volumineuses, et des requêtes depuis des IP hors de votre infrastructure connue. Supabase journalise l'en-tête x-real-ip sur chaque requête.
  3. Vérifiez les objets de stockage. Visitez Storage → Logs et examinez les téléchargements récents de fichiers. Une clé de rôle de service fuitée donne aussi un accès tout-contourner aux buckets privés.
  4. Retirez la clé du contrôle de version. Même après rotation, laisser le JWT dans votre historique git signifie qu'il est découvrable dans le repo public. Utilisez git filter-repo ou BFG Repo-Cleaner pour le nettoyer de l'historique, puis faites force-push (prévenez d'abord les collaborateurs).
  5. Rescanner après correction. Lancez un nouveau scan FixVibe contre l'application redéployée. Le résultat secrets-de-bundle devrait disparaître. Confirmez qu'aucun JWT service_role ni aucune chaîne sb_secret_* ne reste dans aucun chunk.

Prévenir la fuite dès le départ

La correction structurelle est une discipline de nommage plus des garde-fous au niveau des outils :

  • Ne préfixez jamais la clé de service avec NEXT_PUBLIC_*, VITE_* ou tout autre préfixe qui intègre dans le bundle. La convention de nommage est la frontière — chaque framework la respecte.
  • Gardez la clé de service hors du .env entièrement sur la machine du développeur. Lisez-la depuis un gestionnaire de secrets (Doppler, Infisical, variables d'env chiffrées Vercel) lors du déploiement, ne la commitez jamais localement.
  • <strong>Mark every Supabase client construction with explicit context.</strong> Files named <code>supabase/browser.ts</code> use the anon key; files named <code>supabase/server.ts</code> use the service-role key with <code>import 'server-only'</code> at the top. The <code>server-only</code> import causes a build error if a client component tries to consume the module.
  • <strong>Add a pre-commit hook that greps for JWT-shaped strings.</strong> <code>git diff --staged | grep -E 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+'</code> catches both anon and service tokens before they leave your machine.
  • Ajoutez un garde CI qui scanne la sortie du build. Après next build, cherchez la chaîne service_role dans la sortie de .next/static/chunks/. Faites échouer le build si quelque chose correspond.
bash
# Pre-commit hook: refuse any staged JWT-shaped string.
git diff --staged \
  | grep -E 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+' \
  && echo "JWT detected in staged changes — refusing commit" \
  && exit 1

# CI gate: fail the build if "service_role" shipped to the static bundle.
grep -RE 'service_role|sb_secret_' .next/static/chunks/ \
  && echo "Service-role credential leaked into bundle" \
  && exit 1

Questions fréquentes

À quelle vitesse les attaquants trouvent-ils réellement les clés de rôle de service Supabase fuitées ?

Les scanners de bundles publics ratissent les nouveaux déploiements en quelques minutes. Des chercheurs ont documenté des exploits fonctionnels contre de nouveaux projets Supabase en moins d'une heure depuis le premier déploiement. Traitez toute exposition de rôle de service comme une fenêtre de 60 minutes, pas de 60 jours.

Faire tourner la clé suffit-il, ou dois-je supposer une exfiltration de données ?

La rotation invalide la clé fuitée mais n'annule pas les données déjà extraites. Si vos tables contiennent des PII, des données de paiement ou toute donnée réglementée, vous pouvez avoir une obligation de notification au titre du RGPD (72 heures), du CCPA ou de HIPAA. Auditez les logs et consultez un conseiller juridique si l'audit montre des accès suspects.

RLS peut-il me protéger si la clé de rôle de service fuit ?

Non. La sécurité au niveau des lignes est entièrement contournée par le claim service_role. C'est par conception — la clé existe précisément pour que le code backend puisse sauter RLS pour les opérations d'administration. L'atténuation est de s'assurer que la clé n'atteigne jamais un contexte où un attaquant peut la lire.

Cela s'applique-t-il au nouveau modèle de clés publiable / secret Supabase (<code>sb_publishable_</code> / <code>sb_secret_</code>) ?

Oui — classe de risque identique. La clé sb_secret_* est le nouveau format de clé secrète qui remplace le JWT de rôle de service pour les projets plus récents. Tout ce qui porte sb_secret_* dans un bundle est tout aussi catastrophique qu'un JWT de rôle de service fuité. Le détecteur secrets-de-bundle de FixVibe correspond aux deux formes.

Qu'en est-il de la clé anon / publiable — est-elle sûre dans le bundle ?

Oui, par conception. La clé anon est destinée à vivre dans le navigateur et c'est ce qu'utilise chaque client web Supabase. Sa sécurité dépend entièrement de la configuration correcte de RLS sur chaque table publique. Voir l'article Scanner RLS Supabase pour ce qu'il faut vérifier.

Étapes suivantes

Lancez un scan FixVibe contre votre URL de production — le check secrets-de-bundle est gratuit, sans inscription, et signale l'exposition de service_role en moins d'une minute. Associez ceci à l'article Scanner RLS Supabase pour vérifier que la couche RLS fait son travail, et à la Liste de contrôle de sécurité des buckets Supabase Storage pour verrouiller l'accès aux fichiers. Pour le contexte sur pourquoi les outils IA génèrent cette classe de fuite si fiablement, lisez Pourquoi les outils de codage IA laissent des failles de sécurité.

// scannez votre surface baas

Trouvez la table ouverte avant qu'un autre ne le fasse.

Entrez une URL de production. FixVibe énumère les fournisseurs BaaS avec lesquels votre application communique, identifie leurs endpoints publics et signale ce qu'un client non authentifié peut lire ou écrire. Gratuit, sans installation, sans carte.

  • Offre gratuite — 3 scans / mois, sans carte d'inscription.
  • Identification BaaS passive — aucune vérification de domaine requise.
  • Supabase, Firebase, Clerk, Auth0, Appwrite et plus.
  • Prompts de correction IA sur chaque résultat — collez-les dans Cursor / Claude Code.
Lancer un scan BaaS gratuit

aucune inscription requise

Clé de rôle de service Supabase exposée en JavaScript : ce que cela signifie et comment la trouver — Docs · FixVibe