API-Schlüssel im Browser offengelegt? So prüfen Sie OpenAI-, Claude- und Gemini-Keys
Ruft eine Web-App OpenAI, Claude oder Gemini direkt aus dem Browser auf, bleibt der API-Schlüssel dort sichtbar und kann über die DevTools kopiert werden. Mit einem kurzen Check im Network-Tab lässt sich das bestätigen.

Posted on Nov 2 • Originally published at apidog.com
Si tu aplicación web llama a OpenAI, Claude o Gemini directamente desde el navegador, tu clave de API queda expuesta en el navegador, y cualquiera que abra DevTools puede copiarla. Puedes confirmarlo en 2 minutos: abre la pestaña Red, envía una solicitud de IA y busca un encabezado Authorization, x-api-key o x-goog-api-key que vaya al proveedor. Si ves tu clave ahí, rótala hoy y mueve la llamada detrás de una ruta de servidor.
A continuación: la comprobación, el orden de corrección y cómo tu agente de programación puede probar la ruta corregida.
Una clave de API expuesta en el navegador es un secreto que se envía dentro del código de tu frontend o del tráfico de red, donde cada visitante puede leerlo. Si el navegador envía la clave, el usuario puede copiarla y llamar al proveedor a tu costa.
La guía de claves de API de Gemini de Google dice “No codifiques directamente las claves de API en aplicaciones web o móviles” porque “Las claves compiladas en código del lado del cliente pueden ser extraídas por los usuarios”, y te indica que “ejecutes un servidor proxy backend para hacer las llamadas reales a la API”. La guía de seguridad de claves de API de OpenAI da la misma regla: enruta las solicitudes a través de tu propio backend en lugar de desplegar la clave en el cliente.
El README de openai-node dice que el soporte para navegador está deshabilitado por defecto “para evitar exponer tus credenciales secretas de API”, y tienes que establecer dangerouslyAllowBrowser: true para activarlo. El SDK de TypeScript de Anthropic usa el mismo nombre de opción, y su API solo acepta llamadas de navegador (CORS) cuando la solicitud lleva el encabezado anthropic-dangerous-direct-browser-access: true, como documentó Simon Willison cuando se lanzó.
El patrón es común en aplicaciones creadas rápidamente con constructores de aplicaciones de IA y agentes de programación: el camino más corto que funciona es un fetch desde un componente de React con la clave en una variable VITE_ o NEXT_PUBLIC_. Las claves robadas luego se revenden para inferencia masiva, como se trata en nuestra publicación sobre claves de API de IA robadas y LLMjacking, y tu factura es donde lo notas.
Ejecuta estas comprobaciones contra producción, no contra localhost.
Para un escaneo de terminal de la salida de tu build:
grep -rnoE "sk-(proj-|ant-)?[A-Za-z0-9_-]{20,}|AIza[0-9A-Za-z_-]{35}" dist/ build/.next/static/ 2>/dev/null grep -rn "dangerouslyAllowBrowser" dist/ build/.next/static/ 2>/dev/null `
Una salida vacía es un aprobado. Google dice que las nuevas claves de AI Studio creadas desde el 28 de mayo de 2026 son “claves de autenticación”, cuyo formato puede diferir de AIza, así que busca también en el bundle generativelanguage.googleapis.com. Apruebas solo cuando el navegador habla con tu propio dominio (por ejemplo, /api/chat ) y no aparece ningún nombre de host de proveedor ni clave en ningún sitio.
Rotar primero cierra el agujero de hoy; el cambio de arquitectura lo cierra para siempre.
Despliega la clave nueva en el servidor antes de revocar la antigua, o tu función de IA dejará de funcionar. Nuestra guía sobre mejores prácticas para la rotación de claves de API cubre la rotación sin tiempo de inactividad. En el paso 4, la guía de seguridad de claves de OpenAI recomienda límites de gasto con aplicación estricta, porque las alertas por sí solas no detienen el tráfico; un presupuesto de facturación de Google Cloud te alerta pero no detiene el uso por sí mismo.
Una ruta proxy backend es un pequeño endpoint de servidor que recibe el prompt del usuario, añade la clave de API en el servidor, llama al proveedor y devuelve solo la respuesta. El navegador nunca ve la clave. Aquí tienes una ruta mínima de Next.js para OpenAI; Claude y Gemini siguen la misma forma:
`ts // app/api/chat/route.ts (runs on the server only) import OpenAI from "openai"; import { getSession } from "@/lib/auth"; // your auth helper import { checkRateLimit } from "@/lib/limits"; // your per-user limiter
const client = new OpenAI({ [REDACTED CREDENTIAL] }); // no NEXT_PUBLIC_ prefix
export async function POST(req: Request) { const session = await getSession(req); if (!session) return new Response("Unauthorized", { status: 401 });
if (!(await checkRateLimit(session.userId, 20))) { // 20 requests per minute return new Response("Too many requests", { status: 429 }); }
const { message } = await req.json(); if (typeof message!== "string" || message.length > 4000) { return new Response("Bad request", { status: 400 }); }
const response = await client.responses.create({ model: process.env.OPENAI_MODEL!, // pin the model server-side input: message, });
return Response.json({ reply: response.output_text }); // return the answer, nothing else } `
Para Claude y Gemini, usa sus SDK con ANTHROPIC_API_KEY o GEMINI_API_KEY. Las restricciones de sitio web e IP de Google ayudan, pero cualquiera con curl puede enviar cualquier encabezado Referer, así que trátalas como una segunda capa. El único caso justo para llamadas desde el navegador es una herramienta de tipo trae tu propia clave donde cada usuario pega su propia clave.
Mover la clave es la mitad del trabajo; la otra mitad es demostrar que sigue movida después de la próxima función que escriba tu agente. Deja que el agente que creó la ruta la pruebe con Apidog CLI. Configúralo una vez:
bash npm install -g apidog-cli@latest apidog login --with-token <YOUR_TOKEN> npx -y skills add https://apidog.com # pick your agent when prompted
Luego dale a Claude Code, Codex, Cursor o el agente que uses un [REDACTED PROMPT] Create Apidog test cases in project for POST /api/chat on our staging environment that assert:
El agente lee el esquema, valida su payload, escribe los casos y los ejecuta:
`bash apidog test-case category --project <id> apidog cli-schema get test-case-create apidog cli-schema validate test-case-create --file case.json apidog test-case create --project <id> --file case.json apidog run --test-case <caseId> --project <id> -e <envId> -r cli,json `
La segunda aserción es la que más importa: falla en el momento en que un objeto de error del proveedor o un campo de depuración empieza a devolver tu clave al cliente. Pon el mismo paso apidog run... -r junit en tu pipeline para que cada despliegue lo vuelva a comprobar; nuestra guía de Apidog CLI para CI/CD muestra la configuración, y Apidog CLI en Claude Code cubre el lado del agente. El plan gratuito de Apidog cubre hasta 4 usuarios, así que un equipo pequeño puede ejecutar esto sin una licencia de pago.
Para el lado del repositorio del mismo problema, claves confirmadas en Git en lugar de enviadas al navegador, consulta nuestra comprobación de fuga de claves de API con un escáner de secretos. Si tus agentes llaman a herramientas que manejan datos de clientes, probar agentes de IA en busca de fugas de datos cubre la siguiente capa.
¿Cómo sé si mi clave de API de OpenAI está expuesta en el navegador? Activa una función de IA con la pestaña Red de DevTools abierta. Una solicitud a api.openai.com con un encabezado Authorization: Bearer [REDACTED]-... significa que está expuesta. Busca también en los scripts cargados sk- y dangerouslyAllowBrowser.
¿Es seguro poner una clave de API en una variable de entorno NEXT_PUBLIC_ o VITE_? No. Esos prefijos existen para copiar valores en el bundle del cliente. Cualquier clave de proveedor almacenada bajo ellos se envía a cada visitante. Usa una variable sin prefijo solo para servidor y léela dentro de una ruta de servidor.
¿Restringir una clave de API de Gemini a mi sitio web la hace segura en el navegador? Ayuda, pero un script fuera del navegador puede enviar cualquier encabezado Referer. La propia guía de Google recomienda un proxy backend para aplicaciones cliente.
Encontré mi clave expuesta. ¿Qué debo hacer primero? Crea una clave nueva, despliégala en el servidor y luego revoca la antigua. Después, mueve la llamada detrás de una ruta autenticada con límites de tasa por usuario, y configura límites de gasto del proveedor.
¿Puede mi agente de programación corregir y probar esto por mí? Sí. Pídele que mueva la llamada al proveedor a una ruta de servidor, luego usa Apidog CLI para crear y ejecutar pruebas que verifiquen un 401 sin sesión, que no haya patrones de clave en las respuestas y un 429 al superar tu límite de tasa.