Bases de la sécurité
Votre clé API OpenAI est exposée dans votre frontend. Changez-la.
Une clé API OpenAI exposée dans votre frontend ne peut être liée à aucun domaine. Changez-la aujourd'hui, passez par votre serveur et plafonnez la dépense.

En bref
- Une clé API OpenAI exposée dans votre frontend est le cas où l'alerte a raison. Aucun réglage ne rend une clé de ce genre sans danger dans un navigateur.
- C'est un jeton au porteur, il suffit donc de la détenir. Il n'existe aucune restriction de domaine qui l'attache à votre propre site, comme il en existe une pour une clé Google.
- Changez-la aujourd'hui dans le tableau de bord OpenAI, déplacez l'appel derrière un endpoint qui vous appartient, et posez une limite de dépense sur le projet.
- Nous en avons trouvé une dans 33 applis sur 30 998 scannées. Rare, et les 33 sont ressorties avec la note D ou F.
Ouvrez votre appli dans un navigateur, affichez le code source de la page et
cherchez-y sk-proj-. Si une longue chaîne remonte, votre clé API OpenAI est
exposée dans votre frontend, et tous les visiteurs que vous avez jamais eus
auraient pu la copier.
Voici la partie que la plupart des conseils sur le sujet ratent : une clé OpenAI n'est pas une clé Google avec un autre préfixe, et rien de ce que vous pouvez régler dans un tableau de bord ne la met à l'abri là où elle est. Une clé Google Maps a sa place dans votre page, et un réglage gratuit la protège. Une clé OpenAI n'a nulle part de réglage équivalent, et c'est pourquoi la seule première consigne honnête est de la changer.
Entre le 12 et le 14 août 2026, nous avons passé neuf vérifications externes sur 30 998 applis en ligne, construites avec Lovable, Bolt, v0, Replit et Base44. Une clé OpenAI est apparue dans 33 d'entre elles. Les 33 sont revenues avec la note D ou F, parce qu'un seul constat critique plafonne la note quoi que l'appli ait réussi par ailleurs. Les chiffres complets sont dans notre rapport de scan.
Une clé API OpenAI exposée dans votre frontend est-elle un problème ?
Oui. C'est le cas où l'alerte a raison.
Une clé OpenAI est un jeton au porteur, et le mot porte toute l'explication :
qui la porte peut s'en servir. Elle voyage dans un en-tête qui dit
Authorization: Bearer sk-proj-…, et les serveurs d'OpenAI ne demandent rien de
plus. Ni quel site l'a envoyée. Ni de quel pays elle vient, ni si l'expéditeur
est vous.
Pensez à un billet de train plutôt qu'à un passeport. Un contrôleur ne vérifie pas à quel nom est un billet, parce que le détenir est toute la qualification. Voilà ce qui rend un billet digne d'être volé et un passeport le plus souvent pas.
Une clé imprimée dans votre appli est donc un billet que vous avez tendu à chaque visiteur. La plupart ne regarderont jamais. Ceux qui regardent ne sont généralement pas des gens : des scrapers automatiques parcourent les pages publiques en ramassant des chaînes en forme de clé, et ils n'ont pas besoin de savoir qui vous êtes pour trouver la vôtre.
Pourquoi la variable d'environnement ne l'a pas cachée
Parce qu'un build de frontend compile les variables d'environnement dans le fichier qu'il livre.
C'est l'étape qui donne aux gens la certitude que la clé est à l'abri. Vous
l'avez sortie de votre code pour la mettre dans un fichier .env, vous l'avez
nommée VITE_OPENAI_API_KEY ou NEXT_PUBLIC_OPENAI_API_KEY, et maintenant le
code nomme une variable là où la clé se trouvait. Rien n'a changé dans l'appli
livrée. L'outil de build a remplacé cette variable par sa valeur en sortie, et la
valeur est posée dans le JavaScript que votre visiteur télécharge.
La documentation de Vite le dit sans détour : les variables portant le préfixe
VITE_ sont exposées dans le code source côté client après le bundling, et les
informations sensibles comme les clés d'API n'ont pas leur place dans l'une
d'elles, parce que les valeurs sont empaquetées dans votre source. Les préfixes
VITE_ et NEXT_PUBLIC_ ne sont pas un coffre. Ils sont une déclaration que
vous avez compris que cette variable est publique.
Une variable d'environnement a bien fait une chose réelle pour vous : elle a gardé la clé hors de votre dépôt, où l'aurait croisée quiconque lit votre code. Vos visiteurs ne lisent jamais votre code. Ils lisent le fichier que votre build en a tiré.
Pourquoi vous ne pouvez pas la restreindre comme une clé Google
Parce qu'OpenAI ne propose pas de restriction de ce type.
Si vous avez lu quelque chose sur une clé API Google dans un frontend, vous avez croisé un correctif de cinq minutes : ouvrez la clé dans la console Google Cloud, posez une restriction de référent HTTP, et la clé imprimée dans votre page fonctionne sur votre site et renvoie une erreur partout ailleurs. Ce conseil est juste pour une clé Google, et il ne se transpose pas.
Il n'y a aucun champ sur une clé OpenAI pour « uniquement depuis yourapp.com ». Pas de liste de domaines autorisés, pas de vérification de référent, pas de restriction par IP qui survive à un navigateur. Ce qu'OpenAI vous donne à la place se situe sur le compte derrière la clé : à quel projet elle appartient, ce que ce projet a le droit de dépenser dans le mois, et si la clé existe encore. Cela limite ce qu'une clé volée peut coûter. La clé elle-même continue de fonctionner depuis partout jusqu'à ce que vous la supprimiez.
Ce que fait vraiment dangerouslyAllowBrowser
Elle coupe une protection, et son nom est la documentation.
La bibliothèque JavaScript officielle d'OpenAI refuse de s'exécuter dans un
navigateur par défaut. Le README dit que la prise en charge du navigateur est
"disabled by default to avoid exposing your secret API credentials", et
qu'activer dangerouslyAllowBrowser "can be dangerous because it exposes your
secret API credentials in the client-side code".
Si votre appli appelle OpenAI depuis le navigateur, cette option est à true
quelque part dans votre code, car la bibliothèque ne démarre pas sans elle.
Quelqu'un a tapé le mot dangerously pour faire disparaître un message d'erreur.
C'est en général ainsi que ce constat se fabrique, et la bibliothèque vous
l'avait dit en premier.
L'option a de vrais usages, et ils sont tous étroits : un outil interne dont vous connaissez chaque utilisateur, une clé de développement provisoire, une clé si finement limitée que la dépenser ne coûte rien. Une appli publique sur l'internet ouvert n'est aucun de ceux-là.
Ce que ça coûte quand quelqu'un trouve votre clé
Une facture, et une appli qui cesse de fonctionner.
La facture est la partie que les gens attendent. Les requêtes de quelqu'un d'autre sont portées à votre compte, et les appels de modèle ne sont pas bon marché à l'échelle d'un projet secondaire. Le plus souvent, celui qui gère l'appli s'en aperçoit sur une facture plus lourde que celle du mois précédent sans raison qu'il puisse désigner.
La panne est la partie qu'il n'attend pas. Votre compte a des limites de débit, et le trafic d'un inconnu les consomme. Votre propre appli se met à renvoyer des erreurs aux heures où quelqu'un d'autre travaille, ce qui se lit comme un bug et non comme un vol, alors on passe une journée à déboguer la mauvaise chose.
Il y a un troisième coût, et il dépend de la portée donnée à la clé. Une clé API authentifie tous les appels que le projet auquel elle appartient peut faire, donc une clé largement autorisée atteint tout ce qui est stocké là : les fichiers téléversés sur le compte, les modèles affinés, les assistants que vous avez construits. Vérifiez ce que la clé pouvait réellement atteindre avant de décider qu'il ne s'agissait que d'argent.
Comment appeler OpenAI depuis votre appli sans livrer la clé
Mettez quelque chose qui vous appartient entre votre visiteur et OpenAI.
La forme est la même partout. Votre appli appelle un petit endpoint qui est le vôtre. Cet endpoint détient la clé, appelle OpenAI et renvoie la réponse. Le navigateur ne voit jamais la clé, parce que la clé ne quitte jamais votre serveur.
Où vit cet endpoint dépend de ce avec quoi vous avez construit :
- Supabase dans votre stack : une Edge Function, avec la clé enregistrée comme secret dans le tableau de bord Supabase.
- Déployé sur Vercel ou Netlify : une fonction serverless sous
/api, avec la clé dans les variables d'environnement côté serveur du projet. - Lovable, Bolt ou Replit : chacun a son propre magasin de secrets. La règle ne change pas, et le piège non plus : un magasin étiqueté secrets envoie quand même la valeur au navigateur si le code qui la lit s'exécute là.
Deux choses valent la peine tant que vous y êtes. Donnez à votre endpoint une limite de débit, parce qu'un endpoint qui appelle OpenAI pour quiconque demande est la même facture par une route plus lente. Et posez une limite de dépense mensuelle sur le projet OpenAI, le seul contrôle qui met un plancher sous le pire scénario.
Si votre appli utilise l'API Realtime d'OpenAI pour la voix, le navigateur a réellement besoin d'un identifiant, et OpenAI documente comment lui en donner un : votre serveur frappe un secret client à courte durée de vie et remet celui-là à la page. Le billet existe toujours, il expire en quelques minutes, et c'est votre propre serveur qui l'a émis.
Comment trouver gratuitement chaque clé que votre appli livre
Commencez à la main, cela coûte cinq minutes et ne demande rien à installer.
Affichez le source de votre site en ligne et cherchez-y sk-proj- pour une clé
OpenAI, sk-ant- pour une clé Anthropic, AIza pour Google et eyJ pour un
jeton Supabase.
Ce qui échappe à cette méthode, c'est le JavaScript que la page charge ensuite, et sur une appli vibe-codée c'est presque tout. Notre scanner ouvre votre appli dans un vrai navigateur, attend l'arrivée des bundles et lit ceux-ci au lieu du HTML. Il décode aussi chaque jeton Supabase et rapporte le rôle écrit à l'intérieur, si bien qu'une clé qui a sa place dans votre page revient marquée comme correcte au lieu d'être noyée dans un mur de rouge.
La vérification des clés est l'une des neuf, et les huit autres sont la raison pour laquelle une note vous en dit plus qu'une recherche :
| Ce que le scan regarde | La question à laquelle il répond |
|---|---|
| Clés secrètes dans votre code | Une clé d'API payante ou d'admin est-elle lisible par n'importe qui ? |
| Règles de la base de données | Un inconnu peut-il lire les lignes de vos utilisateurs sans compte ? |
| Fichiers privés | Des fichiers .env ou des dumps de base sont-ils téléchargeables ? |
| En-têtes de sécurité | Les protections côté navigateur sont-elles activées ? |
| Buckets de stockage | N'importe qui peut-il lister les fichiers déposés par vos utilisateurs ? |
| Source maps | Votre code source d'origine est-il publié à côté de l'appli ? |
| APIs ouvertes et CORS | Vos endpoints répondent-ils à n'importe quel site qui demande ? |
| Expiration du certificat | Le HTTPS est-il valide et pas sur le point d'expirer ? |
| Renouvellement du domaine | Le nom est-il renouvelé avant que quelqu'un puisse le prendre ? |
Vous obtenez une note, un score et les décomptes à l'écran en une vingtaine de secondes, sans compte. Donnez une adresse e-mail et la liste détaillée vient avec, accompagnée d'un correctif écrit pour votre builder que vous pouvez coller tel quel.
Trois choses qu'il ne fera pas, et ce sont les raisons pour lesquelles on peut le
pointer sans risque sur une appli en ligne : il ne se connecte jamais, il n'écrit
jamais rien, et il ne garde jamais une clé qu'il trouve. Un secret exposé est
conservé sous forme d'indice masqué du genre sk-proj-…a1b2, et la vraie valeur
est jetée. Scannez votre appli, ou lisez d'abord
ce que regarde chacune des neuf vérifications.
Quoi faire tout de suite
Que faire
- Changez la clé en premier, dans le tableau de bord OpenAI sous API keys. La retirer de votre code ne ferme rien, car l'ancienne valeur reste dans votre historique de versions et dans chaque copie en cache de votre page.
- Posez une limite de dépense mensuelle sur le projet auquel appartient la clé. C'est le seul contrôle qui plafonne ce que cette erreur, ou une prochaine, peut vous coûter.
- Déplacez l'appel derrière un endpoint qui vous appartient, et donnez à cet endpoint sa propre limite de débit. Un navigateur ne devrait jamais détenir une clé qui dépense de l'argent.
- Lisez votre page d'utilisation pour les jours où la clé était active. Changer la clé arrête ce qui se passera ensuite et ne dit rien de ce qui s'est déjà passé.
- Gardez le préfixe
VITE_ouNEXT_PUBLIC_loin de tout ce que vous n'aimeriez pas voir lu par un inconnu. Ces préfixes veulent dire public, et votre outil de build les prend au mot.
Si vous préférez traiter tout cela en une seule fois, la checklist de sécurité en 10 minutes le couvre avec les autres choses à fermer dans une appli fraîchement lancée. Et pour la question plus large de savoir quelles clés ont leur place dans un navigateur, nous avons un guide pour distinguer les clés publiables des clés secrètes et un recensement de ce que 30 998 applis ont réellement livré.
FAQ
Quelqu'un a trouvé ma clé OpenAI dans mon appli. Que faire en premier ?
La changer. Ouvrez votre tableau de bord OpenAI dans API keys, créez une nouvelle clé, mettez la nouvelle sur votre serveur et supprimez l'ancienne. La retirer de votre code n'est pas la même chose, car l'ancienne valeur reste dans votre historique de versions et dans toute copie en cache de votre page. Ensuite, posez une limite de dépense sur le projet et lisez votre page d'utilisation pour les jours où la clé était active.
Puis-je restreindre une clé OpenAI à mon propre domaine, comme une clé Google ?
Non. Une clé API Google accepte une restriction de référent HTTP qui la fait fonctionner sur votre site et échouer partout ailleurs, et c'est pour cela qu'une clé Google dans votre page est le plus souvent sans danger. OpenAI n'offre rien d'équivalent. Il n'y a ni liste de domaines autorisés ni vérification de référent sur une clé API, donc les seuls contrôles dont vous disposez portent sur le compte derrière elle : à quel projet la clé appartient, ce que ce projet a le droit de dépenser, et si la clé existe encore.
La bibliothèque OpenAI a une option dangerouslyAllowBrowser. Est-ce que ça rend la clé sûre ?
Non, et le nom est l'avertissement. OpenAI livre la prise en charge du navigateur désactivée, et son propre README dit que l'option est dangereuse parce qu'elle expose vos identifiants d'API secrets dans le code côté client. L'activer ne change rien à ce que le navigateur peut lire ; cela empêche seulement la bibliothèque de refuser de démarrer. Les cas étroits pour lesquels elle est prévue sont les outils internes dont vous connaissez chaque utilisateur et les clés de développement à courte durée de vie, pas une appli publique.
Combien quelqu'un peut-il dépenser avec une clé qu'il a trouvée ?
Autant que votre compte l'autorise, et c'est pour cela que la limite de dépense compte plus que le montant de la facture que vous avez vue jusqu'ici. Une clé volée puise dans les mêmes limites de débit que votre appli, donc le premier symptôme n'est souvent pas la facture : c'est votre propre appli qui se met à échouer pendant que quelqu'un d'autre travaille. Posez une limite de dépense mensuelle sur le projet et vous avez un plafond sur tout cela.
Je n'ai utilisé la clé que pour une démo rapide. Est-ce que ça compte quand même ?
Oui. Une clé reste active jusqu'à ce que quelqu'un la révoque, et elle ignore qu'elle devait être provisoire. Des scrapers automatiques ramassent en continu les chaînes en forme de clé sur les pages publiques, donc l'âge de la démo joue contre vous plutôt que pour vous. Supprimer la clé prend moins de temps que décider si elle méritait d'être supprimée.