API keys expuestas en el JavaScript del cliente
Todo lo que se envía al navegador — scripts inline, JS empaquetado, source maps — puede leerlo cualquiera. Las claves secretas (OpenAI, la secreta de Stripe, AWS, URLs de bases de datos) incrustadas en el código del frontend están, en la práctica, publicadas.
Qué es
Las herramientas de build insertan las variables de entorno en tiempo de compilación. Si referencias un secreto en el código del cliente, termina en el bundle de JavaScript que descarga cada visitante.
Hay una distinción crucial: las claves publicables/anónimas (pk_live de Stripe, la configuración web de Firebase) están diseñadas para ser públicas, pero las claves secretas (sk_live, claves service role, API keys de proveedores) no lo están y nunca deben llegar al navegador.
Por qué importa
Una clave de proveedor filtrada le permite a cualquiera acumular consumo en tu cuenta — facturas de LLM, cargos de SMS, gasto en la nube — o acceder a los datos que la clave autoriza.
Los atacantes rastrean bundles de JavaScript a gran escala buscando patrones de claves. Un secreto publicado suele empezar a abusarse a los pocos minutos de estar en línea.
Cómo solucionarlo
Llama a las APIs de terceros desde una ruta de servidor o un backend, nunca desde el navegador. El navegador habla con tu endpoint; tu endpoint guarda la clave.
// app/api/summarize/route.ts (server-only)
export async function POST(req: Request) {
const { text } = await req.json();
const r = await fetch("https://api.openai.com/v1/responses", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` },
body: JSON.stringify({ model: "gpt-4o-mini", input: text }),
});
return Response.json(await r.json());
}En Next.js solo las variables con el prefijo NEXT_PUBLIC_ se exponen al navegador. Nunca pongas un secreto detrás de ese prefijo: úsalo solo para valores que pueden ser públicos sin riesgo.
Si un secreto llegó al navegador, revócalo y emite uno nuevo. Quitarlo del próximo build no invalida las copias que ya fueron extraídas.
Preguntas frecuentes
¿Mi clave publicable de Stripe (pk_live) es un problema en el frontend?
No: las claves publicables están hechas para ser públicas. El riesgo es la clave secreta (sk_live), que debe quedarse en el servidor.
¿Puedo simplemente ofuscar la clave?
No. La ofuscación se revierte trivialmente. La única solución es mantener el secreto completamente fuera del cliente.
¿Tu app está afectada?
AppSafe verifica este y docenas de problemas más en un solo escaneo gratis.
Escanear mi app gratisDel blog
Falsos crawlers de IA están buscando tus archivos .env. Así puedes revisar los tuyos
Escáneres de credenciales usan los nombres de crawlers de IA para colarse en las listas de permitidos, y piden un archivo en concreto: tu .env. Cómo comprobar si el tuyo es accesible y cómo protegerlo.
La brecha de Railway: cómo rotar los secretos de tu app sin caídas
Railway pidió a todos sus usuarios que rotaran sus variables de entorno después de que los atacantes fueran a por API keys de IA y de plataformas. Cómo revisar tu exposición, rotarlo todo sin tumbar tu app y hacer que la próxima brecha duela menos.
¿Vas a lanzar una app creada con IA? Revisa estas 7 cosas antes
Las herramientas de IA optimizan para que "funcione", no para que "sea seguro lanzarlo". Estos son los siete problemas que revisamos primero en cualquier app recién lanzada, con la solución para cada uno.
Guías relacionadas
Archivos .env expuestos: cómo los atacantes encuentran tus secretos
Un solo .env accesible puede entregar todo tu stack.
Row Level Security (RLS) en Supabase: protege tus tablas
Tu anon key es pública. RLS es lo único que la separa de tus datos.
Firebase Security Rules: deja de dejar tu base de datos abierta
Tu config de Firebase es pública por diseño. Tus reglas deciden quién ve los datos.
Los source maps en producción filtran tu código fuente
Los .map publicados entregan tu código fuente original.