« Sécurité Vercel » se divise en deux moitiés qu'il vaut mieux ne pas mélanger. La première, c'est ce que Vercel gère pour toi et ce qu'il te laisse configurer dans le tableau de bord : protection des déploiements, variables par environnement, pare-feu, rôles de l'équipe. La seconde, c'est ce que Cursor, v0 ou Bolt écrivent dans ton projet et que Vercel déploie tel quel, avec ses clés publiques et ses routes non protégées. Ce guide explique le modèle de Vercel, passe en revue ce que l'IA fait mal en déployant là, te laisse un vercel.json prêt à coller, un prompt de revue et quatre vérifications de l'extérieur. Le détail de chaque faille est dans la sécurité quand tu déploies sur Vercel.
Partie 1 : comment fonctionne la sécurité sur Vercel
Ce que Vercel fait tout seul
Certificat TLS émis et renouvelé automatiquement, redirection de HTTP vers HTTPS, fonctions serverless isolées entre projets, réseau mondial avec atténuation DDoS et un journal de chaque déploiement avec qui l'a fait et depuis quel commit. Rien de tout ça n'est à configurer. Il pose aussi un en-tête pour que les moteurs de recherche n'indexent pas les previews.
Ce qui est ta configuration
- Deployment Protection. Par défaut, les previews sont publiques pour qui a l'URL. Dans Settings, tu peux exiger un compte Vercel de l'équipe (gratuit), un mot de passe (plans payants) ou limiter par IP. C'est la première case à cocher.
- Variables d'environnement par environnement. Chaque variable est affectée à Production, Preview ou Development. Les clés de production ne devraient pas exister en Preview, et les sensibles sont marquées Sensitive pour ne plus pouvoir être relues depuis le tableau de bord.
- Pare-feu. Vercel Firewall apporte des règles gérées, un mode de défi contre les bots et tes propres règles de limitation par IP ou par route. Elles s'activent depuis le tableau de bord sans toucher au code et sont la réponse à « quelqu'un consomme mon quota OpenAI ».
- Git et déploiements. Chaque push sur n'importe quelle branche déploie. Protège la branche de production sur GitHub, vérifie quels comptes ont accès au projet et impose l'authentification à deux facteurs sur l'équipe.
- Jetons et services. Les jetons de la CLI, ceux de Vercel Blob ou ceux des bases de données intégrées sont des secrets de serveur. Un jeton Vercel à portée d'équipe déploie ce qu'il veut dans tous tes projets.
Ce qui dépend du framework, pas de Vercel
Quelles variables atteignent le navigateur (NEXT_PUBLIC_, VITE_, NUXT_PUBLIC_), si les source maps sont publiées et quels en-têtes sont envoyés, c'est ton framework et ta configuration qui le décident, pas la plateforme. Vercel ne fait qu'exécuter le build. C'est pour ça que deux applis sur Vercel peuvent avoir un A et un F en en-têtes.
Partie 2 : ce que l'IA fait mal en déployant sur Vercel
- Des clés secrètes avec le préfixe public parce que le composant « en avait besoin ». Elles voyagent dans le bundle vers tous les visiteurs. Cherche
sk_live,service_roleouAKIAdans tes chunks. - Des routes de test déployées.
/api/debug,/api/seedou/api/admincréées pour tester et poussées en production sans authentification. - Un cron sans secret. Vercel appelle ta route de cron avec un en-tête
Authorizationportant tonCRON_SECRET; si le handler ne le vérifie pas, n'importe qui déclenche la tâche. - Des fonctions sans limite. Un endpoint qui appelle un modèle ou envoie des e-mails sans plafond par utilisateur ni règle de pare-feu.
- Des fichiers dans public/. Un
.envcopié, unbackup.json, unconfig.yml. Tout ce qui est dans ce dossier est public. - CORS avec joker et identifiants sur les routes d'API, parce que « ça marchait comme ça depuis localhost ».
- Pas de vercel.json. Ni en-têtes de sécurité ni redirection du domaine
.vercel.appvers le tien, qui se retrouve dupliqué sur Google.
Un vercel.json prêt à coller
Des en-têtes de sécurité pour toutes les routes et une redirection du sous-domaine Vercel vers ton domaine. Remplace les deux noms et, si tu utilises Next.js, tu peux mettre les en-têtes dans next.config à la place :
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "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=()" }
]
}
],
"redirects": [
{
"source": "/(.*)",
"has": [{ "type": "host", "value": "mon-projet.vercel.app" }],
"destination": "https://tondomaine.com/$1",
"permanent": true
}
]
}
La Content-Security-Policy va à part parce qu'elle dépend de tes scripts ; commence en mode rapport comme l'explique les en-têtes de sécurité HTTP.
Un prompt de revue avant de déployer
Passe en revue la sécurité de ce projet déployé sur Vercel et ne change rien pour l'instant. Réponds avec une liste :
1. Variables à préfixe public (NEXT_PUBLIC_, VITE_, NUXT_PUBLIC_) contenant des clés secrètes.
2. Routes d'API sans vérification de session, routes de test ou de débogage, et routes de cron qui ne vérifient pas CRON_SECRET.
3. Endpoints appelant des services payants sans limite par utilisateur.
4. Fichiers dans public/ qui ne devraient pas être publics.
5. Routes d'API avec Access-Control-Allow-Origin: * et identifiants.
6. S'il existe un vercel.json ou un next.config avec des en-têtes de sécurité et si les source maps sont désactivées en production.
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|content-security"
curl -sI https://mon-projet.vercel.app | grep -iE "^HTTP|^location"
curl -sI https://mon-projet-git-main-equipe.vercel.app | grep -iE "^HTTP"
for p in .env .env.local config.json backup.zip api/debug api/seed; do printf "%-14s " "$p"; curl -s -o /dev/null -w "%{http_code}\n" "https://tondomaine.com/$p"; done
Attendu : en-têtes présents, un 301 vers ton domaine sur l'URL .vercel.app, un 401 sur l'URL de preview si la protection est active, et 404 sur toutes les routes de la liste. Scanaris fait ces vérifications et une quarantaine d'autres en 30 secondes : il détecte que l'appli est sur Vercel et avec quel framework, cherche des secrets dans le bundle, vérifie source maps, en-têtes, CSP, cookies, CORS, TLS et fichiers exposés, et te donne un fix prompt pour chaque échec à coller dans Cursor, v0 ou Bolt. Si ton appli est en Next.js, le guide Next.js explique quel code tourne sur le serveur et ce qui atteint le navigateur.
Questions fréquentes
Les previews Vercel sont-elles privées ?
Pas par défaut : quiconque a l'URL les ouvre, même si elles ne sont pas indexées. Active Vercel Authentication dans Deployment Protection ; c'est disponible sur le plan gratuit.
Vercel protège-t-il mes routes d'API ?
Non. Une route d'API est une URL publique ; la session, c'est toi qui la vérifies dans le code. Le pare-feu peut limiter les requêtes et freiner les bots, mais il ne décide pas qui est autorisé.
Ai-je besoin de vercel.json si j'utilise Next.js ?
Pour les en-têtes, non : next.config a la fonction headers(). Pour la redirection du domaine .vercel.app vers le tien, tu peux utiliser l'un ou l'autre. L'important, c'est qu'elle existe dans l'un des deux.