Bases de la sécurité
Un endpoint d'API ouvert est-il un problème de sécurité ?
Votre scan a signalé un endpoint d'API ouvert. Que cela compte dépend de ce qui est revenu, et la plupart de ceux trouvés étaient à la plateforme.

En bref
- Un endpoint d'API ouvert signifie qu'un chemin inscrit dans le code de votre application a répondu à une requête sans login, et que ce qui est revenu était du JSON.
- Sur ceux que nous avons trouvés dans 30 926 applications, sept sur dix ont été posés par la plateforme sur laquelle l'application a été publiée, et ils renvoient des réglages.
- La question qui tranche est de savoir si quelque chose dans la réponse décrit une personne. Une liste de prix est publique à dessein. Une liste de vos clients ne l'a jamais été.
Votre scan est revenu avec une ligne qui ne se lit pas comme un verdict : certains endpoints d'API répondent sans login. Quelqu'un vous l'a peut-être dit plus franchement, en parlant d'un endpoint d'API ouvert. En dessous il y a une adresse, et il y a de bonnes chances que vous ne la reconnaissiez pas.
Voici la partie que guide après guide présente de travers : le conseil habituel pour ce constat est de mettre un login devant votre endpoint, et sur la plupart des applications que nous avons scannées il n'y a aucun endpoint à vous devant lequel en mettre un. Sept sur dix de ceux que nous avons trouvés appartiennent à la plateforme sur laquelle l'application a été publiée. Lire ce constat commence donc par déterminer à qui appartient l'adresse, et la réponse se voit le plus souvent dès la première ligne de ce qui revient.
Ce que signifie un endpoint d'API ouvert dans votre rapport
Cela signifie qu'un chemin inscrit dans le code de votre application a répondu à une requête qui ne portait pas de login, et que ce qui est revenu était du JSON.
Trois étapes, et aucune n'est maligne. Nous chargeons votre application dans un navigateur comme le ferait un visiteur, et nous lisons le code que ce navigateur a téléchargé. Dedans se trouvent les adresses que votre application appelle quand elle a besoin de données. Puis nous demandons des données à chacune, sans compte, sans cookie et sans clé. Si une adresse répond avec du JSON qui n'est pas un message d'erreur, elle part au rapport.
Cela rapporte ce qui s'est passé. Ce n'est pas un jugement sur les données, car rien qui se tienne à l'extérieur de votre application ne peut dire si une liste de choses est une liste de choses publiques. C'est pour cela que le constat est formulé ainsi : ces endpoints ont renvoyé des données sans aucune authentification, cela peut être voulu pour des données publiques, vérifiez qu'aucun n'expose d'informations privées.
Le rapport vous tend donc une liste d'adresses à ouvrir. Chacune d'elles demande à être ouverte dans un navigateur déconnecté, et ce sont les premières lignes de la réponse qui tranchent.
Tout endpoint d'API ouvert est-il un problème de sécurité ?
Non. Il y en a trois sortes, et seule la troisième est un problème.
Pensez à un immeuble. Certaines choses y sont faites pour quiconque entre : les horaires près de la porte, les sorties de secours, l'avis annonçant l'entretien de l'ascenseur mardi. Ailleurs dans ce même immeuble il y a un classeur avec les coordonnées des locataires. Depuis le couloir, un tableau d'affichage et un classeur non verrouillé sont deux meubles qu'on peut ouvrir, et la seule façon de les distinguer est de lire ce qu'il y a sur le papier.
| Ce qui a répondu | À qui appartient l'adresse | Où vous en êtes |
|---|---|---|
| Réglages de la plateforme : avis de cookies, interrupteurs | À votre builder, dans toutes les applications qu'il publie | Rien à faire |
| Vos propres données publiques : une liste de prix, un article | À vous, et faites pour être lues | Rien à faire |
| Des lignes sur des personnes : noms, e-mails, commandes | À vous, et accessibles à quiconque détient l'adresse | Fermez-la aujourd'hui |
La première ligne est un tableau d'affichage que quelqu'un d'autre a vissé au mur. La deuxième est un tableau que vous avez accroché exprès. La troisième est le classeur, et il est ouvert depuis aussi longtemps que l'adresse existe.
Comment vérifier ce que renvoient vos endpoints
Ouvrez chacun déconnecté et lisez ce qui arrive. La lecture prend plus de temps que le constat ne le laisse croire, et c'est la seule étape qui répond à la question.
Trouvez les adresses. Ouvrez votre application en production, appuyez sur F12 pour faire apparaître les outils de développement du navigateur, cliquez sur Réseau et rechargez la page. Parcourez les requêtes qui reviennent en JSON. Ce sont les adresses auxquelles votre application va chercher des données, et la liste du rapport en est un sous-ensemble.
Interrogez chacune en inconnu. Copiez une URL, ouvrez une fenêtre de navigation privée pour être déconnecté, et collez-la. Ce que vous voyez est exactement ce que voit à cette adresse n'importe qui sur internet.
Lisez les premières lignes. Trois choses peuvent revenir :
- Une erreur, un refus, ou
[]. L'adresse veut un login, ou il n'y a rien dedans pour un appelant déconnecté. Passez à la suivante. - Des réglages. Des drapeaux, des interrupteurs, une couleur, la liste des fonctionnalités activées, un numéro de version. Personne n'est nommé et rien n'est décrit. Passez à la suivante.
- Des lignes. Une adresse e-mail, le nom d'une personne, le montant d'une commande, le texte d'un message, un numéro de téléphone. Arrêtez-vous ici, c'est celle-là.
Si vous trouvez des lignes, essayez de changer un chiffre dans l'URL avant de
fermer l'onglet. Une adresse qui livre la fiche d'une personne sur id=1 et
celle d'une autre sur id=2 les livre toutes, et cela vaut la peine de le
savoir avant de décider à quel point c'est urgent.
Notre scan gratuit fait les deux premières étapes pour vous : il lit dans le code de votre application les adresses qu'elle appelle, interroge chacune sans login, et liste celles qui ont répondu avec des données. Il prend une vingtaine de secondes et ne demande aucun compte : scannez votre application. La troisième étape est à vous, parce que vous êtes la seule personne à savoir si un nom de cette liste est un vrai client.
La plupart de ceux que nous avons trouvés sont à la plateforme
Lors de notre passage d'août 2026, 3 852 des 30 926 applications où cette vérification a pu obtenir une réponse avaient au moins une adresse qui répond sans login. Sur ce total, 2 705 étaient des applications Base44, et sur Base44 c'est presque toujours la même adresse.
Il s'agit de /api/consent/config, les réglages de cookies de la plateforme.
Nous avons rouvert en septembre un échantillon d'applications Base44 signalées,
et la seule adresse qui a répondu était celle-là. Elle renvoie des réglages, elle
est identique d'une application à l'autre, et les données de personne n'y sont.
Le scanner la rapporte correctement et le propriétaire n'a rien à corriger.
| Plateforme | Applications avec le constat | Applications où la vérification a répondu |
|---|---|---|
| Base44 | 2 705 | 5 419 |
| Domaines propres | 82 | 955 |
| Bolt | 4 | 1 120 |
| Lovable | 8 | 18 518 |
| v0 | 0 | 1 786 |
Une plateforme manque à ce tableau, exprès. Replit représente un bloc important des constats restants, et personne n'en a rouvert un échantillon comme nous l'avons fait pour Base44, donc nous ne savons pas encore à qui sont ces adresses. Publier un chiffre comme étant le problème du propriétaire avant que quiconque l'ait regardé, c'est exactement ainsi qu'un réglage de plateforme Base44 devient une statistique sur des propriétaires négligents. Chacun des chiffres ci-dessus vient de notre scan de 30 998 applications vibe-coded en production, qui publie chaque chiffre avec la base sur laquelle il a été mesuré.
Lisez les deux extrémités de ce tableau ensemble, car l'écart est la partie
utile. Sur Lovable, c'est 8 applications sur 18 518, et sur v0 aucune. Ces
applications n'ont pas de petit serveur à elles : la page parle à Supabase
directement depuis le navigateur, il n'y a donc nulle part de /api/… à vous
que cette vérification puisse trouver. Ce qui protège les données sur une
application comme celle-là, ce sont les règles sur chaque table, et c'est un
autre constat avec une
façon bien à lui de mal tourner.
Quand le JSON est des réglages, et quand ce sont des personnes
Une question tranche : quelque chose dans la réponse décrit-il une personne ?
Les réglages décrivent votre application. Un drapeau disant si le mode sombre est activé, la liste des devises que vous acceptez, la version de quelque chose, le texte d'un bandeau de cookies. Publier cela révèle comment votre application est configurée, et votre application tourne de toute façon sous les yeux de tout le monde.
Les lignes décrivent vos utilisateurs. Un nom, une adresse e-mail, ce que quelqu'un a acheté, ce qu'il a écrit, où il habite. Ce n'est pas une phrase sur une configuration, c'est le contenu du classeur, et cela compte à cause de la banalité du geste qui l'emporte. Il n'y a pas d'effraction. L'adresse est une ligne de texte qui fonctionne dans n'importe quel navigateur, alors elle se retrouve collée dans une conversation de groupe, enregistrée dans les notes de quelqu'un, et appelée à intervalles réguliers par un script que personne ne surveille.
Fermer un endpoint, et pourquoi renommer le chemin ne le ferme pas
Exigez un login à l'adresse, et répondez 401 à un appelant qui n'en a pas.
C'est toute la correction, et elle se pose à l'adresse et nulle part ailleurs. Trois choses qui ressemblent à la correction sans en être une :
- Renommer le chemin, ou le sortir de votre code. C'est celle dont il faut se méfier, parce que le constat disparaît. Celui qui avait déjà l'URL l'a toujours, elle est dans les historiques de navigation et les journaux serveur, et le classeur est encore ouvert, simplement sans étiquette sur le devant.
- Restreindre votre en-tête CORS. Cela décide quels autres sites peuvent lire une réponse dans le navigateur de quelqu'un, et rien d'autre ne le consulte. Un script ou un terminal lit la même adresse dans les deux cas, et c'est pourquoi le constat du joker est une autre question.
- Filtrer dans l'application. Si la page cache les lignes qu'elle ne devrait pas montrer, l'adresse les envoie quand même. Le filtrage doit se produire avant que la réponse ne parte.
Il y a une quatrième option, et sur une page publique c'est souvent la meilleure : ne plus avoir l'endpoint du tout. Si les données ne servent qu'à votre propre page, la page peut les recevoir pendant sa construction, et l'adresse sort de votre code avec elles.
À quoi ressemble la correction en code
Deux choses, dans le handler qui répond à l'adresse : déterminer qui demande, et s'arrêter si la réponse est personne.
Vous ne taperez peut-être jamais cela vous-même, et ce n'est pas grave. Lisez-le quand même, parce que c'est ce avec quoi vous vérifiez que votre builder a bien fait ce que vous lui avez demandé. Voici la forme d'avant, celle que le scan a trouvée :
app.get('/api/orders', async (req, res) => {
const orders = await db.orders.findMany()
res.json(orders)
})
Et après :
app.get('/api/orders', async (req, res) => {
const user = await getUserFromRequest(req)
if (!user) {
return res.status(401).json({ error: 'Not signed in' })
}
const orders = await db.orders.findMany({ where: { userId: user.id } })
res.json(orders)
})
Deux choses ont changé et toutes les deux comptent. Le 401 est la porte. Le
where est la raison pour laquelle la porte vaut la peine : sans lui, un
visiteur connecté peut lire les commandes de tous les autres clients, ce qui
fait un public plus petit pour les mêmes données et reste le mauvais.
Sur les Edge Functions de Supabase, lisez la configuration avant d'écrire quoi
que ce soit. Les Edge Functions vérifient le jeton de l'appelant d'elles-mêmes :
la référence de configuration de Supabase met verify_jwt à true par défaut,
donc une fonction qui répond à des inconnus est une fonction où quelqu'un a
désactivé cela, soit par une ligne dans supabase/config.toml, soit en
déployant avec --no-verify-jwt :
[functions.orders]
verify_jwt = false
Si votre fonction doit être privée, supprimez ces deux lignes et redéployez. Ne les laissez que là où l'endpoint doit vraiment répondre à tout le monde, ce qui est le cas que la documentation de Supabase elle-même prend en exemple : un webhook de paiement. À l'intérieur de la fonction, le SDK actuel vous donne un client déjà restreint à la personne qui a appelé :
import { withSupabase } from 'npm:@supabase/server'
export default {
fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => {
const { data } = await ctx.supabase.from('orders').select()
return Response.json(data)
}),
}
ctx.supabase s'exécute en tant que l'appelant, ce sont donc vos règles de
sécurité au niveau des lignes qui décident de ce qui revient, la même protection
sur laquelle repose le reste de votre application, et
ce qu'il vaut la peine de vérifier à part.
Le prompt à coller dans votre builder
Si vous construisez dans Lovable, Bolt, Cursor, Replit ou v0, donnez-lui ceci. Laissez-le en anglais, quelle que soit la langue dans laquelle vous lisez cet article, parce que c'est la langue dans laquelle ces outils raisonnent, et remplacez les deux parties entre crochets par ce que dit votre propre rapport :
A security scan of [my-app.com] found these API endpoints answer
without any authentication: [/api/orders, /api/users].
Please look at each one and decide whether it is meant to be public.
For the ones that are not, require a valid session or API token and
return 401 otherwise. Make sure each one returns only the rows that
belong to the person asking, not the whole table filtered in the UI.
For any that must stay open, make sure they return only non-sensitive
data and add rate limiting so they cannot be abused.
Tell me what you changed for each endpoint, and do not rename or
remove the paths.
Cette dernière phrase est là exprès. Quand on demande à un modèle de faire disparaître un constat, il prend parfois le chemin le plus court et déplace l'adresse, qui est le seul résultat ayant l'air d'une réussite au scan suivant sans rien changer.
Ce qu'il faut faire maintenant
Que faire
- Ouvrez chaque adresse signalée dans une fenêtre de navigation privée et lisez ce qui revient. C'est l'étape que le rapport ne peut pas faire à votre place.
- Si la réponse est des réglages et que l'adresse en est une que vous n'avez jamais écrite, elle est à votre builder et il n'y a rien à corriger. Cherchez le chemin dans la documentation de votre plateforme avant d'y dépenser quoi que ce soit.
- Si la réponse contient un nom, un e-mail ou une commande, exigez un login à cette adresse dès aujourd'hui et renvoyez un 401 à quiconque n'en a pas.
- Ne renommez pas le chemin et n'en supprimez pas la référence. Le constat disparaît et l'adresse continue de répondre.
- Essayez de changer un id dans l'URL sur votre propre application. Une adresse qui sert une fiche à un inconnu les sert en général toutes.
Les adresses de cette liste ont toutes été écrites par quelqu'un qui savait ce qu'il y avait derrière à ce moment-là, et ce qui change, c'est ce qu'il y a derrière. Reeve Care repasse ce scan sur votre application en production selon un calendrier et vous envoie un e-mail quand un résultat se dégrade, ce qui est précisément le cas que le passage déconnecté ci-dessus ne peut pas attraper : ce qu'il surveille et ce qu'il coûte.
Si vous préférez tout traiter d'une traite, la checklist de sécurité en 10 minutes couvre ceci à côté du reste de ce qu'une application fraîchement lancée a tendance à laisser ouvert, et quelles clés sont sûres dans votre frontend est l'autre constat avec lequel les gens arrivent le plus souvent.
FAQ
Que veut dire "endpoint d'API ouvert" dans mon rapport ?
Cela veut dire que nous avons lu le code que votre application envoie à un navigateur, que nous y avons trouvé une adresse à laquelle votre application demande des données, et que nous avons demandé des données à cette adresse sans compte et sans login. Elle a répondu, et la réponse était du JSON. C'est tout le constat. Il rapporte ce qui s'est passé, et ne juge pas si les données étaient privées, car rien à l'extérieur de votre application ne peut le savoir.
Tout endpoint d'API ouvert est-il un problème de sécurité ?
Non. Beaucoup d'adresses sont faites pour répondre à tout le monde : une liste de prix publiée, un article, la liste des fonctionnalités activées. Le problème, c'est l'adresse qui renvoie des lignes appartenant à des personnes, parce qu'elle le fait pour quiconque possède l'URL. Lisez ce qui est revenu et demandez-vous si quoi que ce soit là-dedans décrit une personne.
Mon rapport signale un endpoint que je n'ai pas écrit. Qu'est-ce que c'est ?
En général, celui de votre builder. Les plateformes qui donnent à votre application un petit serveur à elle y glissent aussi quelques adresses à elles, et celles-là sont dans le code de toutes les applications de la plateforme. L'exemple le plus net que nous ayons mesuré, ce sont les réglages de cookies de Base44 sur /api/consent/config, qui représentent 2 705 des 3 852 constats de notre passage d'août 2026. Ils renvoient des réglages, ils sont identiques sur toutes les applications Base44, et rien là-dedans ne vous appartient.
Comment vérifier ce que renvoient les endpoints de mon application ?
Ouvrez votre application en production, appuyez sur F12, cliquez sur Réseau et rechargez. Les requêtes qui reviennent en JSON sont les adresses auxquelles votre application va chercher des données. Copiez chaque URL, ouvrez une fenêtre de navigation privée pour être déconnecté, et collez-les une par une. Lisez ce qui arrive. Une erreur ou une liste vide, c'est très bien. Les lignes contenant des noms, des e-mails ou des montants de commande sont lisibles par quiconque détient cette adresse.
Cacher le chemin suffit-il ?
Non. Renommer l'adresse, ou retirer la référence de votre code, empêche un scanner de la trouver et la laisse répondre exactement comme avant. Celui qui avait déjà l'URL l'a toujours, et elle reste dans les historiques de navigation, les journaux serveur et tout ce qui a parcouru votre site. La correction se fait à l'adresse : exiger un login et répondre 401 à un inconnu.