Fundamentos de seguridad
Clave de API expuesta en el frontend: qué llevan 30.998 apps
Una clave de API expuesta en tu frontend suele ser una clave de Google Maps. Escaneamos 30.998 apps vibe-coded y contamos qué secretos se filtran de verdad.

En resumen
- Una clave de API expuesta en tu frontend es casi siempre de la clase inofensiva. Encontramos una clave digna de mención en 1.332 de 30.998 apps, y 1.080 de ellas solo llevaban una clave de API de Google.
- La clave service_role de Supabase, contra la que advierte cada tutorial, apareció en 3 apps de 30.998. Una clave secreta de Stripe apareció también en 3.
- Las claves que gastan dinero o leen datos por su propia forma aparecieron en 54 apps. Una tabla abierta de Supabase apareció en 2.096.
Alguien abre tu app, pulsa F12 y te dice que hay una clave de API expuesta en tu frontend. La palabra que usa suele ser «filtrada». Rara vez dice de qué clave se trata, y los consejos que encuentras después tratan todas como la misma emergencia.
No son la misma emergencia, y ahora podemos poner cifras a la distancia. Entre el 12 y el 14 de agosto de 2026 pasamos nueve comprobaciones externas a 30.998 apps en funcionamiento creadas con Lovable, Bolt, v0, Replit y Base44, y leímos el JavaScript que cada una entrega a un navegador. Esto es lo que había dentro.
¿Una clave de API expuesta en el frontend es realmente un problema?
Casi nunca, y la forma de ese «casi nunca» está más desequilibrada de lo que esperábamos.
Encontramos una clave digna de mención en 1.332 de las 30.998 apps. En 1.080 de ellas lo único que encontramos fue una clave de API de Google, que son precisamente las credenciales que deben estar en tu página. Lo que protege a esa es un ajuste guardado del lado de Google, y esconderla nunca formó parte del acuerdo.
Las otras 29.666 apps no entregaban nada que nuestra comprobación de secretos
trate como un problema. Esa cifra necesita una matización para ser honesta: las
claves publicables quedan fuera. Una clave anon de Supabase o una clave pk_
de Stripe pertenece al navegador, así que la marcamos como algo que hiciste bien
y nunca entra en estos recuentos.
Qué contamos y qué no pudimos contar
Cargamos cada app como lo hace un visitante, en un navegador real, y leímos el JavaScript que descargaba. Todo lo que sigue es una forma encontrada en ese código.
Reconocemos los formatos de clave que conocemos. Stripe, OpenAI, Anthropic, AWS, Google y Supabase tienen prefijos identificables, y un JWT de Supabase declara su propio rol en texto legible en la sección central. Unas credenciales en un formato que no reconocemos no están en estas cifras, así que léelas como un suelo.
No usamos ninguna clave que encontramos. Ni una sola vez, en ninguna app.
Anotamos el tipo y una pista enmascarada de la forma sk_live_…a1b2, y el valor
real no se escribió en ninguna parte.
No se nombra ninguna app. Ni aquí, ni en el conjunto de datos, ni en nada que publiquemos.
Casi todas son apps publicadas en el dominio propio de un builder. El método completo, la muestra y cada cifra detrás de este artículo están en nuestro informe de escaneo, incluido lo que no pudimos medir.
Qué entregaban en realidad las 30.998 apps
Una tabla, ordenada por la frecuencia con que vimos cada cosa. La comprobación de secretos se completó en todas y cada una de las 30.998 apps, así que cada recuento de abajo es sobre todas ellas.
| Lo que encontramos en el código del navegador | Apps |
|---|---|
| Clave de API de Google | 1.142 |
| Un valor de alta entropía junto a un nombre «secret» o «password» | 204 |
| Clave de OpenAI | 33 |
| Clave de acceso de AWS | 9 |
| Clave de Anthropic | 5 |
Clave service_role de Supabase | 3 |
| Clave secreta de Stripe | 3 |
| Clave restringida de Stripe | 2 |
Las filas suman más de 1.332 porque una app puede llevar dos de estas. Ordena esas mismas 1.332 apps en grupos que no se solapan y el cuadro se vuelve más nítido: 1.080 tenían una clave de Google y nada más, 198 tenían un valor de alta entropía que puede ser o no unas credenciales reales, y 54 tenían una clave que es un secreto genuino por su propia forma.
El segundo grupo merece describirse con cuidado. Un valor de alta entropía junto
a una palabra como secret o password puede ser una credencial viva, o puede
ser un identificador de sesión, un hash de compilación o un token público con un
nombre desafortunado. Lo señalamos como algo que conviene mirar, y desde fuera
nadie puede decirte cuál de esas cosas es.
Las 54 del tercer grupo son lo auténtico. Todas menos dos salieron con nota D o F, porque un solo hallazgo crítico limita la nota a D por muy bien que la app haya hecho todo lo demás. El grupo más grande dentro de ellas es la clave de OpenAI, con 33, y esa no tiene ninguna opción que la haga segura en un navegador.
La clave contra la que todos advierten fue lo más raro que encontramos
Tres apps. Esas son las que entregaban una clave service_role de Supabase, la
que se salta cada regla de tabla que hayas escrito. Una clave secreta de Stripe
apareció también tres veces.
Ponlo frente a la otra mitad del mismo barrido. De las apps que escaneamos, 8.429
nombraban un proyecto de Supabase, y los dos hallazgos caen dentro de ese mismo
grupo. Tres de ellas entregaban la clave service_role. En 2.096 de ellas, al
menos una tabla respondió a una petición sin ningún inicio de sesión, y en 394
esa tabla llevaba un nombre de personas: users, profiles, customers,
orders.
Las 2.096 son un suelo. 4.749 de las 8.429 nunca respondieron a nuestra
comprobación de base de datos, por razones que no vemos desde fuera, y esas
quedan registradas como desconocidas en lugar de como limpias. Las tres claves
service_role son un recuento exacto, porque una clave se lee del código que
cada app entrega.
Por qué los avisos apuntan a la clave equivocada
Solo vemos el exterior de estas apps, así que no podemos decirte por qué. Lo que sí podemos mostrar es qué error sobrevive.
Copiar la clave equivocada de Supabase es genuinamente fácil. En un proyecto
antiguo anon y service_role están una al lado de la otra en el mismo panel
del dashboard, tienen la misma longitud y la misma forma, y
nada se rompe si coges la equivocada.
Aun así solo ocurrió tres veces en 30.998 apps, porque nada te empuja hacia ahí.
Pegar cualquiera de las dos hace que la app funcione.
La tabla abierta sí tiene una fuerza detrás. Se activa Row Level Security, la app deja de mostrar datos, se escribe una política que permite a todo el mundo para que vuelva a funcionar, y desde ese momento el dashboard informa de la tabla como protegida. Activarlo no es lo mismo que estar protegido. Nuestro escaneo califica esa tabla como hallazgo crítico un día en que tu dashboard te está mostrando el interruptor activado y una política en su sitio.
Cómo encontrar gratis una clave de API expuesta en tu app
Empieza a mano, porque cuesta cinco minutos y no necesita instalar nada. Abre tu
sitio en producción, mira el código fuente de la página y busca cuatro cadenas:
AIza para una clave de Google, sk_ para un secreto de Stripe o de un
proveedor de modelos, service_role para la clave de Supabase que ignora tus
reglas, y eyJ para cualquier token de Supabase. Todo lo que salga ya está en
manos de cada visitante que tienes.
Eso te da la página en sí. Lo que se le escapa es el JavaScript que la página
carga después, y por eso nuestro propio escáner abre una app en un navegador real
y lee los bundles en lugar del HTML. Buscar a mano tampoco puede decirte si el
token eyJ que encontraste es la clave anon o la secreta, porque las dos
tienen la misma longitud y la misma forma.
Nuestro escaneo gratuito cubre ambas cosas. Carga tu app en un navegador real, lee el código que llega de verdad, decodifica cada token de Supabase e informa del rol escrito dentro, de modo que una clave publicable vuelve marcada como correcta en lugar de enterrada en un muro de rojo. Obtienes una nota, una puntuación y los recuentos en pantalla en unos 20 segundos sin cuenta. Da una dirección de correo y obtienes además la lista detallada, con un arreglo escrito para tu builder que puedes pegar directamente.
Tres cosas que no hará, y son las razones por las que es seguro en una app en
producción: nunca inicia sesión, nunca escribe nada y nunca se queda con una
clave que encuentra. Un secreto expuesto se guarda como una pista enmascarada del
tipo sk_live_…a1b2, y el valor real se descarta.
Escanea tu app, o lee primero
qué mira cada una de las nueve comprobaciones.
Qué hacer, en el orden que sugieren las cifras
Qué hacer
- Identifica la clave antes de reaccionar. El prefijo lo resuelve para Stripe y para las claves de Supabase nuevas; en una clave de Supabase antigua decide el campo
roledentro del token. - Si es una clave de Google, restríngela en vez de esconderla. Restricción de Sitios web, tu dominio, solo las API que uses, más un tope de cuota diaria. Gratis, unos cinco minutos, sin cambiar código.
- Si es una clave secreta de verdad, rótala primero. Borrarla de tu código no cierra nada, porque el valor antiguo sigue en tu historial de versiones y en las copias en caché de tu sitio.
- Después ve a leer las reglas de tus tablas, que es donde las cifras sitúan la exposición real. Empieza por las tablas que contienen personas.
- Revisa facturación y registros tras cualquier exposición de una clave secreta. Rotar detiene lo que pase a partir de ahora, y no dice nada de lo que ya pasó.
Recorre la lista entera de una sentada con la lista de seguridad de 10 minutos, que cubre la clave y las reglas de tablas junto a las otras cosas que conviene cerrar en una app recién lanzada. Y si la mitad de base de datos de este artículo es la que te preocupa, tiene su propio recuento: quién puede leer tu base de datos de Supabase.
Preguntas frecuentes
¿Cómo sé si mi clave de API se ha filtrado?
Abre tu sitio en producción, mira el código fuente de la página y busca las formas: AIza para una clave de Google, sk_ para un secreto de Stripe o de un proveedor de modelos, y eyJ para un JWT de Supabase. Todo lo que aparezca ya está en manos de cada visitante. Nuestro escaneo gratuito hace esa misma lectura desde fuera e informa de lo que puede ver en unos 20 segundos, sin cuenta para obtener la nota.
¿Una clave de API escrita en el código es siempre un problema de seguridad?
No, y creer lo contrario es justo lo que enseña a la gente a ignorar el aviso. Algunas claves se publican a propósito: una clave anon de Supabase, una clave pk_ de Stripe y una clave de configuración web de Firebase están diseñadas para vivir en el navegador, y lo que protege tus datos son las reglas que hay detrás. Una clave secreta es el caso contrario y su sitio es un servidor. El prefijo te dice cuál de las dos tienes delante.
Me dicen que mi clave de Supabase está expuesta. ¿Es la mala?
Casi con seguridad no. Las dos claves de Supabase se parecen, así que lee el rol dentro del token o comprueba el prefijo: anon y sb_publishable_ están pensadas para ser públicas, service_role y sb_secret_ no. Encontramos una clave service_role en 3 apps de 30.998, así que las probabilidades están muy del lado de la inofensiva. Si resulta ser la secreta, rótala hoy mismo en el panel de Supabase.
¿De qué debería preocuparme en su lugar?
De las reglas sobre las tablas de tu base de datos. De las apps donde pudimos completar esa comprobación, más de la mitad tenía al menos una tabla que respondía a una petición sin ningún inicio de sesión, y en 394 de ellas la tabla abierta llevaba un nombre de personas: users, profiles, customers, orders. Eso es mucho más común que cualquier clave filtrada y mucho más silencioso, porque la app funciona exactamente igual en ambos casos.
He quitado la clave de mi código. ¿Ya está cerrado?
No por sí solo. El valor antiguo sigue existiendo en tu historial de versiones y en cualquier copia en caché de la página, así que quien ya lo recogiera puede seguir usándolo. Lo que cierra de verdad la puerta es rotar la clave en el panel del proveedor, y ese es el primer paso, no el último. Después revisa la facturación y los registros por si hay uso que no puedas explicar.