Saltar al contenido
← Volver al blog
seguridadapps

¿Clave de API expuesta en el frontend? Cómo saberlo y arreglarlo

Cómo revisar si una clave secreta viaja en el código del navegador de tu app, qué claves pueden ser públicas y cómo pasar las secretas a un servidor.

Por Equipo Devonauts6 min de lectura
Read in English →
Líneas densas de código JavaScript en una pantalla oscura, vistas en ángulo

Si una clave secreta de API está en el código de tu frontend, cualquiera que abra tu sitio puede leerla, aunque esté en una variable de entorno, en un archivo aparte o dentro de JavaScript minificado. La solución es revocarla, crear una nueva y mover cada llamada que la necesite a un servidor (una Edge Function, una función serverless o tu backend), al que el navegador le pide las cosas. Las claves públicas, como la publishable de Stripe o la de Supabase, están hechas para verse y no son el problema.

En esta guía verás cómo revisar tu app desde afuera, cómo distinguir una clave pública de una secreta, cómo se ve el arreglo paso a paso y cómo evitar que vuelva a pasar con el próximo prompt.

¿Cómo sé si mi app expone una clave de API?

Lo puedes revisar en diez minutos solo con el navegador. Hazlo en el sitio publicado, no en la vista previa, porque eso es lo que reciben tus visitantes.

  1. Abre la app, haz clic derecho, elige Inspeccionar y ve a la pestaña Sources (en Firefox, Depurador).
  2. Pulsa Ctrl + Shift + F (o Cmd + Option + F en Mac) para buscar en todos los archivos cargados.
  3. Busca los prefijos con los que suelen empezar las claves secretas: sk_live, sk_test, sk-, sb_secret_, service_role, secret, Bearer.
  4. Abre la pestaña Network, usa la app con normalidad (inicia sesión, usa la función principal) y revisa las peticiones. Si el navegador manda un encabezado Authorization directo a una API externa como OpenAI o SendGrid, la clave está en el navegador.
  5. Revisa también el código. En un proyecto con Vite, toda variable que empieza con VITE_ se copia al paquete del navegador. En Next.js pasa lo mismo con NEXT_PUBLIC_. Si guardaste un secreto con ese prefijo, es público.

Si encuentras algo, da por hecho que ya lo copiaron. Hay programas automáticos que buscan justo esas cadenas.

¿Qué claves pueden estar en el navegador y cuáles no?

No todo lo que encuentres es una filtración. Varios servicios separan a propósito sus claves en una mitad pública y otra secreta.

Clave¿Puede ir en el navegador?Por qué
Publishable key de Stripe (pk_live_…)SíSolo sirve para iniciar pagos, no para verlos ni reembolsarlos
Secret o restricted key de Stripe (sk_…, rk_…)NoPuede leer clientes, reembolsar y mover dinero
Publishable key o anon de SupabaseSí, con Row Level Security activoSolo obtiene lo que tus políticas permiten
Secret key o service_role de SupabaseNoSe salta por completo Row Level Security
Configuración web de FirebaseSí, con reglas de seguridadEl acceso lo deciden tus reglas
Clave de Google Maps para navegadorSí, si está restringidaLimítala a tus dominios y a las APIs que usas
Claves de OpenAI, Anthropic, Gemini y otras de IANoCualquiera puede gastar tu saldo
Contraseñas de correo, SMS o base de datosNoDan acceso total para enviar o leer en tu nombre

Una clave "pública" solo es segura si lo que hay detrás está cerrado. Una clave publishable de Supabase con Row Level Security apagado es tan peligrosa como una secreta, porque la base de datos le responde a cualquiera. Lo explicamos en si la clave anon de Supabase es segura.

¿Por qué las herramientas de IA ponen claves secretas en el frontend?

Porque es el camino más corto a una vista previa que funcione. Cuando pides "agrega resúmenes con IA" o "manda un correo de bienvenida", el código más rápido llama al proveedor directamente desde el componente de React con la clave pegada al lado. Funciona a la primera y nada te avisa que está mal.

Hay otros dos caminos que terminan igual:

  • Un secreto se guardó como VITE_OPENAI_KEY o NEXT_PUBLIC_STRIPE_SECRET porque sin el prefijo el código no podía leerlo.
  • Una clave se pegó en un prompt o en un archivo de configuración y terminó en GitHub, donde queda en el historial aunque borres la línea.

¿Cómo arreglo una clave de API expuesta?

El orden importa. Si primero mueves el código y revocas después, la clave vieja sigue sirviendo mientras tanto.

1. Revoca y reemplaza la clave

Entra al panel del proveedor, crea una clave nueva y revoca o borra la expuesta. Quitarla del código no sirve por sí solo: la copia que alguien ya tomó sigue funcionando hasta que el proveedor la desactive. Si algo que no puedes actualizar enseguida usa esa clave, crea primero la nueva, cambia todo y revoca la vieja ese mismo día.

2. Revisa para qué se usó

Mira la página de uso o los registros del proveedor durante los días en que la clave estuvo pública. Picos raros, peticiones desde países donde no tienes usuarios o cobros que no reconoces indican que la usaron. Si es una clave de IA, en qué hacer si se filtró tu clave de OpenAI vemos la parte del cobro.

3. Pasa la llamada a un servidor

Crea una función pequeña del lado del servidor que haga solo lo que el frontend necesita: "resume este texto", "manda este correo", "crea una sesión de pago". El navegador llama a tu función; tu función guarda la clave y habla con el proveedor.

Navegador  ->  /functions/resumir  (verifica que haya sesión)
                    |
                    v
             Proveedor de IA  (clave leída de un secreto del servidor)

La clave va en el almacén de secretos de la función (los secrets de las Edge Functions de Supabase, o las variables de entorno de Vercel o Netlify sin prefijo público), nunca en un archivo que cargue el navegador.

4. Protege la función nueva

Una función de servidor que cualquiera puede llamar es un atajo gratis a tu cuenta de pago. Haz que verifique que la petición viene de un usuario con sesión, que valide el tamaño de lo que recibe y que limite cuántas veces puede llamarla cada usuario. Lo explicamos en cómo limitar el uso de funciones con IA.

5. Limpia el historial

Si la clave llegó a un commit de Git, quitarla de la última versión no basta. Lo que te protege de verdad es haberla rotado (paso 1); reescribir el historial es orden adicional. La guía de GitHub para remediar un secreto filtrado explica las dos cosas.

¿Cómo confirmo que quedó arreglado?

Repite la revisión del principio en el sitio publicado después de desplegar. Vuelve a buscar los prefijos en Sources, mira en Network que el navegador ahora llama a tu función y no al proveedor, y prueba que el proveedor rechaza la clave vieja. Por último, llama a tu función sin sesión: debe negarse.

¿Cómo evito que vuelva a pasar?

  • Ten una lista corta de qué variables son públicas y cuáles secretas, y nunca le pongas VITE_ o NEXT_PUBLIC_ a un secreto.
  • Agrega una regla al proyecto en tu herramienta de IA: "Nunca llames APIs de pago desde el navegador; crea una función de servidor".
  • Activa secret scanning y push protection en GitHub para que un commit con un formato de clave conocido quede marcado.
  • Configura límites de gasto y alertas en cada proveedor, para que una filtración llegue como aviso y no como factura.

Nuestro checklist de seguridad para apps hechas con IA reúne esta revisión con las demás que conviene hacer antes de lanzar.

Respuestas rápidas

¿Una clave en una variable de entorno ya es segura? No. Depende de dónde se use. Si el build del frontend la lee, termina en el paquete del navegador.

¿Puedo esconderla ofuscándola o cifrándola en JavaScript? No. El navegador tiene que descifrarla para usarla, así que cualquiera puede hacer lo mismo.

¿La publishable key de Stripe es una filtración? No. Está hecha para ser pública. Solo las secret y restricted keys deben quedarse en el servidor.

¿Tengo que borrar mi repositorio de GitHub? No. Revoca la clave con el proveedor. Borrar o reescribir el repositorio no desactiva una copia que alguien ya hizo.

¿Quieres que alguien lo revise contigo?

El chequeo de salud gratis mira lo que tu app publicada expone desde afuera, incluidas claves en el paquete del navegador. Si prefieres que una persona revise el código, pase las llamadas a un servidor y mire tus reglas de base de datos, eso lo cubren nuestra revisión de seguridad de Supabase y los planes de mantenimiento, o puedes contarnos qué encontraste.

¿Tu app sigue trabada?

Pasa el chequeo gratis con la URL de tu app, o pide la Auditoría de rescate de $299: un ingeniero senior revisa el código y te envía un informe escrito en 2 días hábiles.