Les outils de code IA comme Lovable, Bolt, Cursor ou Replit transforment un prompt en application fonctionnelle en un après-midi. Ce qu'ils ne font pas par défaut, c'est raisonner comme un attaquant. Le code marche, la démo est belle, et les failles de sécurité n'apparaissent qu'une fois les vrais utilisateurs (ou les bots) arrivés.
Cet article est une checklist opérationnelle. Chaque bonne pratique indique quoi vérifier, pourquoi c'est important, et un court exemple à adapter. Si vous voulez d'abord la vue d'ensemble — ce qu'est la sécurité du vibe coding et pourquoi les apps générées par IA sont exposées — commencez par notre guide complet de la sécurité vibe coding.
1. Gardez les secrets hors du code côté client
Tout ce qui se retrouve dans votre bundle JavaScript peut être lu par n'importe qui en ouvrant les DevTools. Cela inclut les variables d'environnement avec un préfixe public comme NEXT_PUBLIC_ (Next.js) ou VITE_ (Vite).
À vérifier :
- Aucune clé secrète (
sk_live_,service_role,sk-,AKIA…) n'apparaît dans le code frontend ou dans une variable publique. - Les appels qui nécessitent un secret passent par une route serveur, une Edge Function ou un backend.
// app/api/checkout/route.ts — exécuté uniquement côté serveur
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!); // pas de préfixe NEXT_PUBLIC_
export async function POST() {
const session = await stripe.checkout.sessions.create({ /* ... */ });
return Response.json({ url: session.url });
}
Les clés publiables (Stripe pk_live_, clé anon Supabase) sont conçues pour être publiques, mais seulement si le reste de votre configuration est verrouillé — ce qui nous amène au point suivant. Pour aller plus loin, lisez Clés API exposées : détecter et corriger.
2. Activez la Row Level Security sur chaque table Supabase
La clé anon de Supabase est faite pour être envoyée au navigateur. Ce qui protège vos données, c'est la Row Level Security (RLS). Sans RLS, toute personne qui possède la clé anon peut interroger vos tables directement via l'API Supabase, sans passer par votre interface.
À vérifier :
- La RLS est activée sur toutes les tables du schéma
public. - Chaque table a des politiques explicites qui définissent qui peut lire et écrire quoi.
alter table public.profiles enable row level security;
create policy "Users can read their own profile"
on public.profiles for select
using (auth.uid() = id);
create policy "Users can update their own profile"
on public.profiles for update
using (auth.uid() = id);
Activer la RLS sans aucune politique bloque tout accès via l'API, ce qui est un point de départ sûr : ajoutez ensuite les politiques une par une selon les besoins de votre app. Notre guide Comment sécuriser votre app Supabase en 10 minutes détaille la RLS, les politiques de stockage et les réglages d'authentification pas à pas.
3. Verrouillez les règles de sécurité Firebase
Firebase repose sur le même modèle : la configuration web est publique, et ce sont les règles de sécurité qui décident de ce que les clients peuvent faire. Des règles laissées en « mode test » (ou réécrites pour tout autoriser afin que l'app fonctionne) laissent Firestore, la Realtime Database ou Storage ouverts.
À vérifier :
- Aucune règle n'autorise
read, write: if true. - L'accès est lié à
request.authet au propriétaire du document.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}
Testez vos règles avec l'émulateur Firebase avant de les déployer, et relisez-les chaque fois que l'IA ajoute une nouvelle collection.
4. Ajoutez les en-têtes de sécurité HTTP
Les en-têtes de sécurité sont une couche de défense peu coûteuse et efficace contre le clickjacking, le MIME sniffing, le retour forcé en HTTP et certains scénarios XSS. Les projets générés par IA les configurent rarement.
À vérifier : Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options, X-Frame-Options (ou frame-ancestors dans la CSP), Referrer-Policy et Permissions-Policy.
// next.config.ts
const securityHeaders = [
{ key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains; preload" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "X-Frame-Options", value: "DENY" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" },
];
export default {
async headers() {
return [{ source: "/(.*)", headers: securityHeaders }];
},
};
Démarrez la Content-Security-Policy en mode Content-Security-Policy-Report-Only, corrigez ce qu'elle signale, puis appliquez-la.
5. Mettez à jour les dépendances vulnérables
Les outils IA choisissent les versions de paquets qu'ils ont vues dans leurs données d'entraînement, et elles peuvent être obsolètes. Les bibliothèques frontend chargées depuis un CDN (une vieille version de jQuery, par exemple) sont tout aussi exposées.
À vérifier :
npm audit --omit=dev # vulnérabilités connues dans les dépendances de production
npm outdated # ce qui est en retard
Commitez votre fichier de lock, mettez à jour régulièrement et activez les alertes automatiques de dépendances sur votre dépôt (Dependabot ou Renovate, par exemple).
6. Ne servez jamais .env, .git ni les source maps
Une erreur étonnamment fréquente consiste à déployer tout le dossier du projet. Si https://votre-app.com/.env ou https://votre-app.com/.git/config renvoie un fichier, vos secrets ou votre code source sont publics.
À vérifier :
- Les fichiers
.env*sont listés dans.gitignoreet ne sont jamais copiés dans le dossier public du build. /.env,/.env.local,/.git/HEADet/.git/configrenvoient une 404 sur votre domaine de production.- Les source maps de production sont désactivées, sauf besoin réel.
curl -s -o /dev/null -w "%{http_code}\n" https://votre-app.com/.env
curl -s -o /dev/null -w "%{http_code}\n" https://votre-app.com/.git/config
# Les deux doivent afficher 404 (ou 403)
7. Protégez vos endpoints d'authentification
L'authentification est le domaine où le code généré par IA « fonctionne » le plus souvent tout en restant fragile. Les formulaires de connexion et d'inscription marchent, mais les protections autour manquent.
À vérifier :
- L'autorisation est vérifiée côté serveur pour chaque route et chaque appel API protégés, pas seulement en masquant des boutons dans l'interface.
- Les sessions utilisent des cookies
HttpOnly,SecureetSameSiteplutôt que des jetons dans lelocalStorage. - Les jetons de réinitialisation de mot de passe expirent et ne sont utilisables qu'une fois.
- Les messages d'erreur ne révèlent pas si une adresse e-mail possède un compte.
// Garde côté serveur : ne jamais laisser le client dire qui est l'utilisateur
const user = await getSessionUser(request);
if (!user) return new Response("Unauthorized", { status: 401 });
if (order.userId !== user.id) return new Response("Forbidden", { status: 403 });
8. Mettez en place du rate limiting
Sans limitation du nombre de requêtes, un formulaire de connexion peut être attaqué par force brute, un formulaire d'inscription inondé de spam, et un endpoint qui appelle une API payante (OpenAI, e-mail, SMS) peut faire exploser votre facture.
À vérifier : connexion, inscription, réinitialisation de mot de passe, formulaires de contact et toute route qui déclenche un service payant.
// Exemple avec @upstash/ratelimit
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(5, "1 m"), // 5 tentatives par minute
});
const ip = request.headers.get("x-forwarded-for") ?? "anonymous";
const { success } = await ratelimit.limit(`login:${ip}`);
if (!success) return new Response("Too many requests", { status: 429 });
Si vous utilisez Supabase Auth ou Firebase Auth, vérifiez leurs limites intégrées et activez une protection CAPTCHA sur les formulaires publics.
9. Relisez vos prompts et le code généré
L'IA construit ce que vous lui demandez. Demandez explicitement de la sécurité, puis relisez le résultat comme vous reliriez la pull request d'un développeur junior.
Un meilleur prompt :
Ajoute l'authentification utilisateur avec validation de session côté serveur, cookies HttpOnly, rate limiting sur la connexion et jetons de réinitialisation de mot de passe qui expirent au bout d'une heure. Ne mets jamais de clé secrète dans le code côté client.
Ce qu'il faut chercher dans le code généré :
- des chaînes en dur qui ressemblent à des clés ou à des mots de passe ;
- des requêtes de base de données construites à partir d'entrées utilisateur sans paramètres ;
dangerouslySetInnerHTMLouinnerHTMLavec du contenu utilisateur ;- des raccourcis « temporaires » comme une RLS désactivée, des règles permissives ou une politique CORS à
*.
10. Scannez votre app avant (et après) la mise en ligne
Les vérifications manuelles s'oublient facilement, et chaque nouveau prompt peut réintroduire un problème déjà corrigé. Intégrez un scan de sécurité à votre routine de mise en production :
- Scannez l'URL de préproduction avant le lancement.
- Corrigez d'abord les problèmes critiques et élevés.
- Relancez un scan après chaque déploiement important.
ScanVibe effectue ces vérifications gratuitement à partir d'une simple URL : clés API exposées dans votre JavaScript, RLS Supabase et règles Firebase, en-têtes de sécurité, bibliothèques vulnérables, fichiers .env et .git exposés, endpoints d'authentification et plus encore. Vous obtenez une note de A à F et, avec un compte gratuit, des instructions de correction pour chaque point en échec.
Checklist sécurité vibe coding (récapitulatif)
| # | Bonne pratique | Vérification rapide |
|---|---|---|
| 1 | Secrets côté serveur | Aucun sk_live_, service_role ou sk- dans le bundle |
| 2 | RLS Supabase | Activée sur chaque table, avec des politiques |
| 3 | Règles Firebase | Pas de if true, accès lié à request.auth |
| 4 | En-têtes de sécurité | HSTS, CSP, nosniff, protection contre l'iframe |
| 5 | Dépendances | npm audit propre sur les dépendances de production |
| 6 | Fichiers exposés | /.env et /.git/config renvoient une 404 |
| 7 | Endpoints d'auth | Autorisation côté serveur, cookies HttpOnly |
| 8 | Rate limiting | Connexion, inscription et routes payantes limitées |
| 9 | Revue des prompts et du code | Sécurité dans les prompts, code IA relu |
| 10 | Scan avant lancement | Scanner la préproduction, corriger, rescanner après chaque déploiement |