
Scanner de sécurité statique local pour les applications Next.js, Supabase et Stripe : 24 vérifications basées sur l'AST pour les clés divulguées, l'absence de RLS et de grants, les webhooks non sécurisés. CLI et GitHub Action.
Analyse de sécurité locale et gratuite pour les applications Next.js + Supabase + Stripe : clés divulguées, RLS et grants manquants, webhooks Stripe non sécurisés.
Votre agent IA a livré l'application. A-t-il aussi livré votre clé secrète Stripe, une table sans RLS, ou un webhook que n'importe qui peut appeler ? Une seule commande le détermine, localement, en moins d'une seconde.
npx github:edtrackai/nextjs-supabase-stripe-security-checker /path/to/your/app
Ce n'est pas encore sur npm, donc npx l'exécute directement depuis ce dépôt GitHub (nécessite Node 18+ et git).
- uses: edtrackai/nextjs-supabase-stripe-security-checker@v0
with:
fail-on: high
Le workflow complet et les permissions sont ci-dessous et dans docs/github-action.md.
Vérificateur RLS Supabase · Sécurité des webhooks Stripe · Analyse de sécurité Next.js · Autorisations de l'API de données Supabase (42501)

git clone https://github.com/edtrackai/nextjs-supabase-stripe-security-checker.git
cd nextjs-supabase-stripe-security-checker && npm install
node bin/nss-security-check.js /path/to/your/app
Node 18 ou version ultérieure. Il y a une seule dépendance (@babel/parser). C'est gratuit et sous licence MIT, ne nécessite aucun compte, n'effectue aucun appel réseau et ne téléverse jamais votre code.
--fail-on=high renvoie le code de sortie 1, et --json fournit une sortie lisible par machine.Publicité (payante, même auteur) : Vous voulez les correctifs ? Launch Audit (12 $ plus TVA le cas échéant) ajoute 28 vérifications, un agent auditeur IA sans outils Edit ni Write, et un plan de correction fichier:ligne.
| Option | Ce qu'elle fait |
|---|---|
--json | Sortie lisible par machine : {tool, version, root, filesScanned, counts, findings[]} |
--fail-on=<sev> | Code de sortie 1 si un résultat est égal ou supérieur à critical / high / medium / low (none n'échoue jamais). Code de sortie 2 en cas d'arguments invalides. |
--list | Affiche le catalogue des vérifications |
--quiet | Omettre la ligne de pied de page sur les outils payants (affichée sur stderr uniquement dans un terminal ; également désactivée avec NO_PROMO=1, CI ou GITHUB_ACTIONS) |
--help | Aide d'utilisation |
En CI : node path/to/bin/nss-security-check.js . --fail-on=high, ou utilisez la GitHub Action (résumé de job, annotations, un commentaire PR épinglé, uniquement GITHUB_TOKEN). Voir l'exemple de workflow et les permissions dans docs/github-action.md.
# .github/workflows/security-check.yml
name: Security check
on: [pull_request]
permissions:
contents: read
pull-requests: write # only for the PR comment; drop it with comment: false
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: edtrackai/nextjs-supabase-stripe-security-checker@v0 # or pin @v0.5.0 / a commit SHA
with:
path: .
fail-on: high
Les modifications sont listées dans CHANGELOG.md (0.5.0 ajoute l'Action).
| ID | Sévérité | Domaine | Vérification |
|---|---|---|---|
| K1 | critique | Clés | Clé secrète/restreinte Stripe live (sk_live_/rk_live_) dans le code source, y compris les clés scindées avec + (la preuve est masquée) |
| K2 | critique | Clés | Variable NEXT_PUBLIC_ ressemblant à un secret (service role, clé secrète, secret de webhook…) |
| K3 | critique | Clés | Fichier .env avec des valeurs suivies par git |
| K4 | critique | Clés | Secret serveur ou client admin Supabase utilisé dans un composant "use client" |
| A1 | élevée | Auth | auth.getSession() utilisé comme source de confiance côté serveur au lieu de getUser()/getClaims() |
| A2 | élevée | Auth | Server Action qui écrit des données sans vérification d'authentification |
| A3 | élevée | Auth | Route API (POST/PUT/PATCH/DELETE) qui écrit des données sans vérification d'authentification (routes webhook, cron et auth exclues) |
| A4 | élevée | Auth | Client admin interrogé avec un id fourni par la requête sans filtre de propriétaire (IDOR) |
| A5 | moyenne | Auth | Redirection ouverte depuis un paramètre de requête |
| R1 | critique | RLS | Table créée sans row level security |
| R2 | critique | RLS | Politique d'écriture avec using (true) / with check (true) |
| R3 | élevée | RLS | Politique qui permet au rôle anon d'écrire |
| R4 | élevée | RLS | Fonction security definer sans search_path fixé |
| R5 | moyenne | RLS | Table dans public sans GRANT explicite. Supabase a annoncé qu'il cesserait les grants par défaut sur les nouvelles tables publiques à partir du 30 oct 2026, mais fin août, un mainteneur de la CLI Supabase a écrit (supabase/cli PR #6337) que le changement de défaut précédent « n'a jamais été déployé » et que les projets hébergés accordaient toujours automatiquement les grants, donc la date pourrait changer : vérifiez ce que fait votre propre projet. Sans grant, la Data API renvoie 42501 |
| R6 | élevée | RLS | grant ... on all tables in schema public / alter default privileges ... grant accordé globalement à anon/authenticated (le correctif rapide pour 42501 qui expose aussi les tables sans RLS) |
| S1 | critique | Stripe | Webhook sans vérification de signature (constructEvent) |
| S2 | critique | Stripe | Webhook qui analyse request.json() au lieu du corps brut |
| S3 | moyenne | Stripe | Webhook sans idempotence sur event.id |
| S4 | élevée | Stripe | Prix ou montant du checkout pris depuis la requête |
| S5 | élevée | Stripe | Accès accordé sur la page de succès du checkout au lieu du webhook |
| S6 | moyenne | Stripe | Déduplication de webhook qui peut avaler un événement en échec : doublons ignorés sans statut pending/completed |
| S7 | faible | Stripe | Période de facturation lue depuis items.data[0] (incorrect pour les abonnements multi-articles depuis l'API 2025-03-31.basil) |
| H1 | moyenne | Durcissement | Aucun en-tête de sécurité dans next.config |
| H2 | moyenne | Durcissement | dangerouslySetInnerHTML avec une valeur non littérale |