Guías de seguridad

Una clave de API se filtró desde código escrito por IA y se usó para cargos fraudulentos: la causa era una vulnerabilidad CVSS 10.0 sin parchear

Una app creada con IA sufrió el robo de su clave de API y cargos fraudulentos. La causa real: un RCE CVSS 10.0 sin parchear. Cómo se halló y cómo evitarlo.

Publicado 2026-06-07 Actualizado 2026-10-06 15 min de lectura
En esta página

Un caso con el que se topan a menudo los desarrolladores indie sin formación en seguridad, con todo detalle identificable eliminado y convertido en lección. Aquí no hay pasos para reproducir el ataque. El objetivo es la defensa, para que el mismo error no te ocurra a ti.

Expediente del caso — INCIDENT FILE
Clase
Fuga de clave de API / facturación fraudulenta
Gravedad
Crítica (un CVSS 10.0 publicado abusado)
Causa raíz
Un RCE preautenticación en el framework web dejado sin parchear durante meses
Alcance de la fuga
Todos los secretos del entorno
Alcance de la ejecución
Quedó dentro de un contenedor sin privilegios (root del host intacto)
Corrección permanente
①actualizar a la versión parcheada ②rotar todas las claves ③monitoreo automático de CVE
10.0
CVSS / peor categoría
meses
cuánto tiempo sin parchear
todo el entorno
alcance de fuga asumido
monitoreo
la prevención más eficaz

«Detuve los cargos» ≠ «resuelto»

Detener la factura es una medida temporal. Cerrar la vía de fuga es una tarea aparte. Solo terminaste cuando hiciste ambas.

Qué pasó (línea de tiempo)

  1. Día 0 — desplegado y en marcha

    Una app construida con ayuda de IA se desplegó y corría en producción.
  2. Un día — la factura se dispara

    La factura de IA en la nube salta de repente. Trabajos masivos en un modelo que jamás se usaría, haciendo tareas que no eran suyas.
  3. Investigación — abuso de terceros

    «Nuestra app se descontroló» no lo explica. Un tercero la ejecutaba con una clave robada.
  4. Rastreo — se investiga la vía de fuga

    «¿De dónde se filtró la clave?». Aquí empezó la investigación de verdad.

Por qué no se detectó al principio

En el orden en que se cometieron los errores — porque los errores son la lección.

1

Decidir la causa demasiado pronto

Primera suposición: «nuestro propio código de respaldo falló». Pero los datos (lo que realmente se procesó) dejaron claro que no podía ser eso.
→ Antes de decidir «culpa mía» o «culpa de ellos», mira primero los datos.
2

Un grep limpio casi cerró la búsqueda

Todo el código, el historial de git, los repos vinculados revisados → ninguna clave en texto plano en ningún sitio. Casi se rinde como «imposible de rastrear». Al mirar solo los archivos, se pasó por alto la fuga en tiempo de ejecución.
3

Ocultar el síntoma pareció una solución

Enmascarar el síntoma en el proxy casi pareció el final. Pero enmascarar deja el RCE en su sitio. Sigue siendo explotable hasta que se arregla la causa.

Un grep limpio no es el visto bueno

Aunque no haya ninguna clave en ningún archivo, una vulnerabilidad puede extraer variables de entorno de un proceso en ejecución. Las fugas ocurren en tiempo de ejecución (RCE, cabeceras HTTP), no solo en archivos. Véase qué es un RCE.

La causa real: un CVSS 10.0 publicado y sin parchear

Una firma extraña en registros de acceso antiguos coincidió rápidamente con la inteligencia de amenazas. El rango de versiones del framework web en uso tenía un RCE preautenticación publicado (CVSS 10.0) que ya estaba siendo explotado activamente, y había corrido sin parchear durante meses.

  • No era un fallo pasivo — era un atacante ejecutando código en el servidor y exfiltrando el entorno.
  • Una cosa limitó el daño: la ejecución quedó dentro de un contenedor sin privilegios (no se tomó el root del host). La revisión de la brecha no encontró puerta trasera persistente, minero ni C2 — el impacto confirmado fue el robo de secretos.
  • Como la base de datos interna era alcanzable, la respuesta asumió que el contenido de la BD también se había filtrado.
Síntoma visible: una factura sorpresa, no reconocida
esto es todo lo que ve el propietario
↑ las claves robadas se revenden / abusan después
se exfiltra todo el entorno (cada secreto)
↑ el atacante ejecuta código arbitrario en el servidor en vivo
causa: un CVSS 10.0 publicado y sin parchear (RCE preautenticación)
La factura sorpresa es solo el síntoma visible. Debajo está la causa: un CVSS 10.0 publicado y sin parchear.

Lección: cuando algo se comporta de forma extraña, sospecha primero de un CVE conocido. No supongas que es un fallo tuyo.

Acota la fuga: ¿dónde vivía esa clave?

Cuando el grep no encuentra nada, cambia la forma de buscar. Haz la lista de dónde estaba escrita la clave abusada, y las vías de fuga candidatas se reducen. Si la clave abusada solo existió en las variables de entorno del servidor de producción, por ejemplo, sospecha del servidor de producción o del proveedor de hosting, no de Git ni del navegador.

Dónde se filtraCausa habitualCómo revisar tu propia configuraciónCómo cerrarla
Historial de Git / repos públicosHacer commit de .env, claves escritas en el códigoEscanea todo el historial con gitleaks git. Revisa las alertas de secret scanning de GitHubRevoca primero y luego bloquéalo antes del commit
JavaScript enviado al navegadorUna clave en una variable NEXT_PUBLIC_, llamar a la API directamente desde el navegadorBusca el prefijo de la clave en la salida del buildLleva la llamada a la API al código del servidor
Una carpeta web pública.env o copias de seguridad colocadas en la carpeta públicaAbre /.env en tu propio sitio y confirma que devuelve 404 o 403Saca los archivos secretos de la carpeta pública
Registros / páginas de errorPublicar con la salida de depuración activada, registrar las cabeceras de las peticiones tal cualRevisa los ajustes de depuración de producción y si Authorization y similares aparecen en los registrosDesactiva la salida de depuración y enmascara los secretos en los registros
El servidor en ejecuciónUna vulnerabilidad publicada (como un RCE) sin parchearCompara la versión que realmente se ejecuta con la versión corregida del avisoActualiza y después sustituye todos los secretos del entorno
El proveedor de hostingUna brecha del lado del proveedorRevisa los boletines de seguridad y los avisos por correo del proveedorGuarda los secretos de forma que los valores no puedan verse después, y rótalos
Tu máquina de desarrolloUn paquete o extensión maliciosoComprueba si las versiones de paquetes o extensiones que instalaste coinciden con un compromiso publicadoQuita esa versión y sustituye los secretos que había en la máquina

Este caso fue la fila del «servidor en ejecución». Las cuatro filas de abajo son vías que no dejan rastro en tu código ni en Git. La Secrets Management Cheat Sheet de OWASP también advierte de que las variables de entorno suelen ser legibles por otros procesos del mismo entorno y pueden acabar en registros o volcados. Así que cuando se abusa de una clave, trata como filtrados todos los secretos guardados en el mismo sitio.

Las claves separadas aceleran la investigación

Si usas una clave distinta por servicio y por entorno (producción frente a desarrollo), la clave abusada por sí sola te dice en qué fila de la tabla estás. Si reutilizas una clave en todas partes, tienes que sospechar de todos los sitios. Cómo separar las claves se explica en cuando una clave de API robada hace que bloqueen tu cuenta de OpenAI.

Cuenta las vulnerabilidades según la versión que realmente se ejecuta

Al revisar las demás dependencias, se reportaron «8 dependencias vulnerables más». También era incorrecto. Se habían contado por el límite inferior en package.json (el rango con el caret ^). Las verdaderamente peligrosas eran solo las 2 dependencias fijadas que habían quedado atrás.

Comprueba tus propias versiones en ejecución

Mira las versiones realmente resueltas, en el lockfile o en el contenedor en ejecución.

# npm: see what's actually installed
npm ls next react react-dom
 
# inside a running container
docker exec <container> npm ls <package>

Los números de aquí son las versiones que realmente se ejecutan, no el ^ de package.json.

Cómo revisar tu propia configuración

Tanto si acabas de ver una factura extraña como si todavía no ha pasado nada, puedes revisarlo en este orden. Cada paso solo mira tu propia cuenta y tu propio servidor.

1

Mira qué clave se usó, y cuándo

En el panel de la API de IA, desglosa el uso y el coste por proyecto (un Workspace, en Anthropic) y por día. El uso en modelos que nunca usas, o a horas en que no se ejecuta nada tuyo, significa que esa clave se filtró. Después empieza por la fila de la tabla correspondiente al lugar donde estaba guardada esa clave.
2

Revisa los archivos enviados al navegador

En Next.js, los valores de las variables de entorno que empiezan por NEXT_PUBLIC_ se insertan en el momento del build en el JavaScript que se envía al navegador. Tras un build, busca el prefijo de tu clave en la salida, por ejemplo grep -rl "sk-" .next/static. Cualquier cosa que aparezca ahí la podía leer cualquiera.
3

Confirma que los archivos secretos no son accesibles desde la carpeta pública

Ejecuta curl -sI https://example.com/.env contra tu propio sitio (sustituye example.com por tu dominio) y confirma que el estado de la primera línea no es 200 (debería ser 404 o 403). Más en auditar archivos secretos en directorios públicos.
4

Compara la versión de producción con el aviso

Como en el recuadro de arriba, ejecuta npm ls dentro del contenedor de producción para ver la versión. osv-scanner scan -L pnpm-lock.yaml comprueba si tu lockfile incluye versiones con vulnerabilidades conocidas.
5

Busca secretos en los registros

Ejecuta gitleaks dir --redact sobre la carpeta donde se guardan los registros de tu app para encontrar claves escritas en ellos. --redact evita que los valores encontrados aparezcan en pantalla.
6

Revisa límites y alertas

OpenAI te permite configurar alertas de gasto y un límite estricto de gasto mensual en la página de límites de su panel. Anthropic te permite configurar un límite de gasto por Workspace. Asegúrate de no tener solo alertas que nunca detienen nada.

Lo que se hizo primero (pasos reproducibles)

1

Revocar de inmediato la clave abusada

Detiene el daño, pero es solo una parte del trabajo.
2

Actualizar el framework a la versión parcheada

Cerrar de verdad el RCE. Tras actualizar, confirma que la firma de la fuga desaparece en los registros.
3

Rotar todos los secretos

Asume que se filtraron. Ordena por «abusable desde cualquier sitio primero»: claves de almacenamiento de objetos → clave de firma de sesiones → claves de API → credenciales de BD.
4

Revisión de la brecha

Comprueba persistencia, cron malicioso, C2 saliente (ninguno aquí).
5

Defensa del lado de la cuenta

Cambia la contraseña, activa MFA, busca claves de API desconocidas.

Prevención: monitorea los CVE de forma automática

Reducido a lo esencial, este incidente fue «un humano pasó por alto un CVSS 10.0 publicado». Las revisiones manuales siempre se pierden cosas. La monitorización automática las detecta.

Escaneo de dependencias que puedes empezar hoy

Gratis para empezar — un paso en CI.

# OSV scanner (Google) checks your lockfile
osv-scanner scan -L pnpm-lock.yaml
 
# On GitHub, enable Dependabot (repo Settings → Security)

Este sitio mismo, conforme a esta lección, monitorea sus propias dependencias en busca de CVE — practicamos lo que recomendamos.

Errores habituales y cómo corregirlos

  • Poner una clave nueva en un servidor que sigue abierto: la misma vía roba también la clave nueva. Detén enseguida la clave abusada, corrige la vulnerabilidad y después termina de sustituir el resto de secretos.
  • Tratar una alerta de presupuesto como un tope: Google Cloud indica que un presupuesto que solo tiene alertas no detiene automáticamente el uso ni el gasto. Si quieres que se detenga, añade un límite que bloquee el uso, como el límite estricto mensual de OpenAI o un límite de gasto de Workspace en Anthropic.
  • Poner una clave de API de IA en un navegador o en una app móvil: cualquier valor que llegue al dispositivo del usuario puede extraerse. Llama a la API de IA desde tu servidor, y que el navegador llame a tu servidor.
  • Borrarla de los archivos o del historial de Git y quedarse ahí: quien ya la copió puede seguir usándola. Revoca primero y limpia el historial después (ver por qué las credenciales filtradas en GitHub siguen siendo válidas, en inglés).
  • Usar la misma clave en desarrollo y en producción: no puedes saber qué lado se filtró, así que tienes que detener ambos. Emite una clave distinta por entorno.

Un ejemplo público: variables de entorno filtradas desde el lado del proveedor

Las fugas que ninguna búsqueda en archivos puede encontrar también ocurren fuera de tu propio servidor. El 19 de abril de 2026, Vercel comunicó un acceso no autorizado a sus sistemas internos. Según la empresa, el compromiso de una herramienta de IA de un tercero usada por un empleado llevó al robo de variables de entorno de algunos clientes que no estaban marcadas como «sensitive» (el ajuste que hace que un valor no pueda verse después de guardarlo).

Vercel recomendó a los clientes revisar y rotar las variables de entorno no marcadas como sensitive, y revisar los registros de actividad y los despliegues recientes. También indicó que borrar los proyectos o la cuenta no basta para eliminar el riesgo.

Los clientes en esa situación podían buscar en su código y en Git todo el día sin encontrar rastro de una fuga. La acción es la misma que en este caso: sustituir todos los secretos guardados en ese sitio. Los pasos están en el incidente de seguridad de Vercel (abril de 2026) (en inglés).

Lecciones

Errores comunes

  • Dar por terminado al «detener los cargos»
  • Relajarse porque el grep está limpio
  • Enmascarar el síntoma en un proxy y sentirlo resuelto
  • Contar vulnerabilidades por el piso de package.json
  • Rotar solo la única clave de la que se confirmó abuso

Defensa correcta

  • Tratar detener los cargos y cerrar la vía de fuga como dos trabajos distintos, y hacer ambos
  • Sospechar también de fugas en tiempo de ejecución (RCE, cabeceras)
  • Actualizar el framework que lo causó
  • Juzgar por la versión realmente en ejecución
  • Reemplazar todo el entorno si se filtra

En resumen: el pico de la factura fue un síntoma, y la causa fue un RCE CVSS 10.0 sin parchear. La causa correcta no se encontró al primer intento; se encontró equivocándose varias veces y volviendo a comprobar.

Leer a continuación

Fuentes

  • OWASP, "Secrets Management Cheat Sheet" (riesgos de las variables de entorno, respuesta ante fugas): cheatsheetseries.owasp.org
  • Documentación de Next.js, "How to use environment variables in Next.js" (inserción de NEXT_PUBLIC_): nextjs.org
  • OSV-Scanner, "Usage": google.github.io
  • OpenAI, "Production best practices" (manejo de claves, alertas y límites): developers.openai.com
  • Centro de ayuda de Claude, "Creating and managing Workspaces" (límites y claves de Workspace): support.claude.com
  • Google Cloud, "Create, edit, or delete budgets and budget alerts": docs.cloud.google.com
  • Vercel, "Vercel April 2026 security incident": vercel.com

FAQ

QSi se filtra una clave de API, ¿basta con revocar solo la clave que se abusó?
A

No. Cuando la vía de fuga está en tiempo de ejecución (un RCE o una fuga de cabeceras), asume que todos los secretos del entorno se filtraron a la vez y rótalos todos. La clave que viste abusada es solo una pequeña parte de lo que se filtró.

QSi un grep en mi código y en git no encuentra claves, ¿estoy a salvo?
A

No necesariamente. Aunque no haya ninguna clave en ningún archivo, una vulnerabilidad del framework puede exfiltrar las variables de entorno directamente del proceso en ejecución. Las fugas también ocurren en tiempo de ejecución, no solo en archivos.

Q¿Qué impide de forma más fiable que esto vuelva a ocurrir?
A

Monitorear tus dependencias en busca de CVE de forma automática. La causa aquí fue que un humano pasó por alto un CVSS 10.0 publicado durante meses; Dependabot u osv-scanner lo detectan automáticamente.

QMi factura de API de IA se ha disparado de repente. ¿Qué hago primero?
A

Primero, desactiva la clave abusada en el panel del proveedor para detener el daño. Después acota la vía de fuga a partir de dónde estaba guardada esa clave, corrige la vulnerabilidad o el error de configuración, y solo entonces sustituye todos los secretos que vivían en el mismo sitio. Revocar solo la clave deja abierta la vía de fuga.

Q¿Cómo averiguo qué clave se filtró?
A

En el panel de la API de IA, desglosa el uso y el coste por proyecto (un Workspace, en Anthropic). La clave detrás del uso en modelos o a horas que tú nunca usas es la filtrada. Si mantienes claves separadas por servicio y entorno, el lugar donde estaba guardada esa clave también te dice la vía de fuga.

QSi configuro una alerta de presupuesto, ¿se detendrán los cargos fraudulentos?
A

No necesariamente. Google Cloud, por ejemplo, indica que un presupuesto que solo tiene alertas no limita automáticamente el uso ni el gasto. Para detener de verdad el uso, configura un límite que lo bloquee, como el límite estricto de gasto mensual de OpenAI o un límite de gasto por Workspace en Anthropic.