« Sécurité Bolt », ce sont deux choses qu'il vaut mieux séparer. La première, c'est le projet Bolt lui-même : ce que tu colles dans le chat, où finissent les variables d'environnement, avec qui tu partages le projet et où il est déployé. La seconde, c'est le code que Bolt génère, presque toujours une SPA Vite et React connectée à Supabase, qui embarque les mêmes cinq ou six failles que d'habitude. Ce guide couvre les deux, avec un fichier d'instructions pour que Bolt applique les règles à chaque génération, un prompt de revue avant de déployer et la façon de vérifier le résultat de l'extérieur.
Partie 1 : protéger ton projet Bolt
Bolt tourne dans ton navigateur, et ça change où vivent les clés
Bolt exécute tout le projet dans le navigateur avec WebContainers. Il n'y a pas de serveur à toi pendant que tu développes, donc toute clé que tu mets dans un fichier .env est dans le projet, et si elle porte le préfixe VITE_, elle finit incrustée dans le bundle déployé. Pour le navigateur, c'est correct seulement avec des clés publiques (l'anon de Supabase, la publishable de Stripe). Les secrètes n'ont pas leur place dans le frontend : elles vont dans une Edge Function Supabase ou une fonction Netlify, et le client appelle la fonction.
Ce que tu colles dans le chat finit dans le code
Si tu colles une clé dans la conversation pour « connecter » un service, le modèle l'écrit là où il en a besoin, c'est-à-dire généralement dans un composant. De là, elle voyage vers tous les visiteurs. La règle : les clés publiques vont dans .env ; les secrètes, dans le tableau de bord du service qui exécute la fonction (Supabase ou Netlify), jamais dans le chat. Et si tu en as collé une par erreur, fais-la tourner : l'historique la conserve même si tu l'effaces du code.
Partager, exporter et déployer
Un lien de projet partagé montre le code complet, .env compris. Avant de partager, vérifie ce qu'il y a dedans. Si tu exportes vers GitHub, mets le dépôt en privé et garde .env dans .gitignore. Le déploiement en un clic va sur Netlify, sur un sous-domaine .netlify.app ou ton propre domaine ; Netlify fournit le TLS et la redirection vers HTTPS, mais pas d'en-têtes de sécurité, et les variables d'environnement de production se configurent dans son tableau de bord, pas dans le .env du projet.
Supabase est à toi
L'intégration Supabase crée des tables, des policies et des fonctions depuis le chat. RLS, buckets et réglages Auth restent ta responsabilité, et Bolt fait les mêmes erreurs que Lovable avec les policies. Le guide de sécurité pour Supabase contient trois requêtes SQL pour auditer le projet en une minute.
Partie 2 : les failles que Bolt met dans ton code
- Des clés secrètes dans les composants. Un appel à OpenAI ou Stripe depuis React avec la clé dedans. Cherche
sk_,service_roleetBearerdans ton bundle déployé. - Des tables sans RLS ou avec des policies
using (true). Quand une requête échoue sur les permissions, le modèle ouvre la policy au lieu de la corriger. - Des Edge Functions sans authentification. Le template répond à n'importe qui avec
Access-Control-Allow-Origin: *; si la fonction dépense de l'argent, n'importe qui peut le dépenser. - Des vérifications seulement dans l'interface. La page d'administration est cachée si tu n'es pas admin, mais l'API répond quand même.
- Des source maps en production. Certains templates Vite embarquent
build.sourcemap: true; ça publie ton code original à côté du minifié. - Invisible pour l'IA et les moteurs de recherche. Le HTML arrive vide et les bots de ChatGPT ou Perplexity ne voient rien. Si la landing compte, prérends-la ou sépare-la. Détail dans pourquoi les applis construites avec l'IA sont invisibles pour l'IA.
- Pas d'en-têtes de sécurité. Ni CSP, ni HSTS, ni X-Frame-Options. Sur Netlify, ils s'ajoutent avec un fichier.
Un bloc pour que Bolt l'applique toujours
Bolt lit le fichier .bolt/prompt de ton projet comme instructions permanentes. Crée le fichier et colle ceci :
Règles de sécurité de ce projet :
- Ne mets jamais de clés secrètes dans le code du frontend ni dans des variables VITE_. Les intégrations avec des clés secrètes vont dans une Edge Function Supabase ou une fonction Netlify qui lit la clé dans ses variables d'environnement.
- Toute nouvelle table a le RLS activé et une policy explicite par opération. N'utilise pas using (true) ni with check (true) sauf sur du contenu public en lecture seule, et préviens-moi quand tu le fais.
- Toute fonction serveur vérifie le JWT de l'utilisateur, restreint Access-Control-Allow-Origin à notre domaine et valide l'entrée.
- Les permissions d'administrateur sont vérifiées dans le RLS ou sur le serveur, jamais seulement dans l'interface.
- Les fichiers des utilisateurs vont dans des buckets privés avec des policies et des URL signées.
- build.sourcemap reste désactivé en production.
- Mets un vrai titre, une vraie meta description et de vraies balises Open Graph dans index.html.
Et les en-têtes pour Netlify, dans un fichier public/_headers déployé avec l'appli :
/*
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Un prompt de revue avant de déployer
Passe en revue la sécurité de ce projet et ne change rien pour l'instant. Réponds avec une liste :
1. Clés ou jetons dans le code du frontend ou dans des variables VITE_, avec fichier et ligne.
2. Tables sans RLS et policies avec using (true) ou with check (true).
3. Fonctions serveur qui ne vérifient pas le JWT, qui répondent avec Access-Control-Allow-Origin: * ou qui ne valident pas l'entrée.
4. Actions d'administrateur protégées seulement dans l'interface.
5. Buckets publics contenant des fichiers d'utilisateurs.
6. build.sourcemap activé et absence du fichier _headers.
7. Métadonnées de index.html encore celles du template.
Pour chaque point, propose le changement exact et attends ma confirmation.
Vérifie le résultat de l'extérieur
curl -sI https://tondomaine.com | grep -iE "strict-transport|x-frame|x-content-type"
curl -s https://tondomaine.com | grep -oE '/assets/[^"]+\.js' | head -1
curl -s https://tondomaine.com/assets/index-XXXX.js | grep -oE "sk_live_[A-Za-z0-9]+|service_role|eyJhbGciOi[A-Za-z0-9_-]{20,}" | head -3
curl -sI https://tondomaine.com/assets/index-XXXX.js.map | head -1
Attendu : en-têtes présents, aucune clé dans le chunk et un 404 sur la source map. Ensuite, sonde l'API Supabase sans session comme l'explique le guide Supabase. Scanaris fait ces vérifications et une quarantaine d'autres en 30 secondes : il détecte que l'appli est faite avec Bolt, cherche des secrets dans le bundle, vérifie source maps, en-têtes, CORS, cookies et fichiers exposés, sonde les tables Supabase sans session et contrôle si ton contenu est lisible sans JavaScript. Pour chaque échec, il te donne un fix prompt à coller dans le chat Bolt, et il peut rescanner chaque jour, parce qu'une régénération peut ramener une faille corrigée.
Questions fréquentes
Les variables VITE_ sont-elles privées ?
Non. Vite incruste dans le bundle tout ce qui commence par VITE_ ; c'est sa façon de dire « ceci est public ». Les clés secrètes ne portent pas ce préfixe et ne se lisent pas depuis le frontend.
Puis-je mettre des en-têtes de sécurité sur Netlify ?
Oui, avec le fichier _headers dans le dossier public ou avec netlify.toml. Netlify les applique au déploiement suivant ; vérifie avec curl.
Que faire si j'ai collé une clé secrète dans le chat Bolt ?
Fais-la tourner chez le service d'origine même si tu l'as effacée du code : l'historique du projet et les déploiements précédents la conservent. Ensuite, ajoute-la dans le tableau de bord Supabase ou Netlify et demande à Bolt de déplacer l'intégration dans une fonction.