Vibe coding: por qué el código generado por IA llega lleno de vulnerabilidades

Vibe coding: por qué el código generado por IA llega lleno de vulnerabilidades

La inteligencia artificial ha cambiado la forma de programar. Ya no hace falta escribir cada función desde cero: podemos describir una idea, pedir una implementación, iterar sobre ella y tener una aplicación funcional en muy poco tiempo. Ese enfoque, conocido como vibe coding, ha reducido enormemente la barrera de entrada para crear software.

El problema aparece cuando la velocidad sustituye a la comprensión. Un modelo puede generar una interfaz impecable, una API que responde correctamente y una integración con base de datos que parece terminada, pero eso no significa que haya entendido las fronteras de confianza de la aplicación. Autenticación, autorización, secretos, dependencias, validación de entrada y lógica de negocio siguen necesitando decisiones explícitas.

El riesgo no es que la IA “programe mal” de forma aleatoria. Es que tiende a optimizar el camino más directo para cumplir la petición. Y el camino más directo para que algo funcione no siempre es el más seguro cuando el usuario deja de comportarse como esperaba el desarrollador.

Nota: los ejemplos de código y arquitectura de este artículo son ilustrativos y están orientados a análisis defensivo y formación en seguridad.

En esta guía


Qué cambia realmente con el vibe coding

Usar IA para programar y hacer vibe coding no son exactamente lo mismo. Un desarrollador puede utilizar un asistente para completar funciones, escribir pruebas o explicar una librería y seguir manteniendo el control completo sobre la arquitectura. El vibe coding lleva la delegación más lejos: gran parte de la implementación se describe en lenguaje natural y se acepta después de comprobar que aparentemente hace lo que se pidió.

Esto introduce una diferencia importante. En el desarrollo tradicional, muchas decisiones de seguridad aparecen porque alguien conoce el sistema y sabe que debe tomarlas. En un flujo guiado por prompts, si una propiedad no está en la especificación, el agente puede no tener ninguna razón para implementarla.

# Flujo con revisión
Idea → diseño → IA genera → revisión → pruebas → seguridad → despliegue

# Flujo puramente orientado a velocidad
Idea → prompt → IA genera → funciona → despliegue
                              ↑ aquí empiezan muchos problemas

La cuestión no es quién escribió las líneas de código. La cuestión es quién verificó las suposiciones que hay detrás.


Por qué una aplicación puede funcionar y seguir siendo insegura

Funcionalidad y seguridad responden a preguntas diferentes. Una prueba funcional comprueba que un usuario puede descargar su factura. Una prueba de seguridad pregunta si también puede descargar la factura de otra persona. La primera confirma el camino esperado. La segunda comprueba qué ocurre cuando alguien manipula el sistema.

Los agentes son muy buenos resolviendo objetivos locales: hacer que una prueba pase, eliminar un error, conectar una API o completar una pantalla. El problema aparece cuando una solución local rompe una propiedad global. Habilitar CORS para cualquier origen elimina un error. Dar más permisos resuelve un problema de acceso. Confiar en un identificador enviado por el frontend hace que una consulta funcione. Ninguna de esas decisiones garantiza que la arquitectura siga siendo segura.

Un ejemplo clásico es un endpoint de facturas:

# Funciona, está parametrizado y exige login
@app.get("/api/invoices/<invoice_id>")
@login_required
def invoice(invoice_id):
    row = db.execute(
        "SELECT * FROM invoices WHERE id = ?",
        (invoice_id,)
    ).fetchone()

    return jsonify(dict(row))

No hay SQL injection y existe autenticación. Sin embargo, sigue faltando la autorización sobre el objeto. Si el identificador pertenece a otro usuario, la aplicación puede devolver información que nunca debería haber salido.

# La consulta incorpora también la propiedad de autorización
row = db.execute(
    "SELECT * FROM invoices WHERE id = ? AND user_id = ?",
    (invoice_id, current_user.id)
).fetchone()
El código generado por IA no debe evaluarse solo preguntando “¿funciona?”. La pregunta útil para seguridad es “¿qué ocurre cuando alguien intenta utilizarlo de una forma que no estaba prevista?”.

Los fallos que más merece la pena buscar

La mayor parte de los problemas de seguridad asociados al código generado por IA no son nuevos. Son vulnerabilidades conocidas que aparecen en implementaciones creadas muy deprisa y con especificaciones incompletas.

ÁreaPatrón habitualQué revisar
AutorizaciónSe valida la sesión, pero no la propiedad del recurso.IDOR/BOLA, roles, organizaciones y endpoints administrativos.
Entrada del usuarioLos datos llegan directamente a consultas, comandos, plantillas o rutas.SQLi, command injection, SSTI, traversal y validación.
SSRFEl backend consume una URL proporcionada por el usuario.Acceso a servicios internos, metadata cloud y redirecciones.
SecretosClaves y tokens se incrustan para acelerar una integración.Repositorio, historial, frontend, logs y contexto del agente.
ConfiguraciónSe relajan controles para resolver errores rápidamente.CORS, debug, buckets, RLS, IAM y permisos de base de datos.
DependenciasEl agente instala paquetes sin suficiente comprobación.Procedencia, versión, scripts de instalación y paquetes inexistentes.

El punto más delicado suele ser la autorización. Ocultar un botón en el frontend no protege un endpoint. Tener login no significa que cada usuario pueda acceder únicamente a sus objetos. Y utilizar un backend gestionado no elimina la necesidad de configurar correctamente las reglas de acceso.

También conviene prestar especial atención a funciones que reciben URLs, nombres de fichero, identificadores, parámetros de organización o roles. Son datos pequeños que a menudo cruzan fronteras de confianza importantes.


El agente también forma parte de la superficie de ataque

Los asistentes actuales ya no se limitan a devolver texto. Pueden leer el repositorio, editar archivos, ejecutar comandos, instalar dependencias, consultar servicios externos y modificar pipelines. Cuando eso ocurre, la seguridad del agente pasa a ser tan importante como la seguridad del código que genera.

Un README, una issue, una pull request, un comentario o la salida de una herramienta pueden terminar dentro del contexto del modelo. Si ese contenido contiene instrucciones maliciosas y el agente dispone de terminal o acceso a archivos sensibles, un problema de prompt injection puede tener consecuencias reales.

$ "Analiza este repositorio, instala lo necesario y haz que funcione."

Para una persona, la documentación es información que se interpreta con criterio. Para un agente, documentación e instrucciones pueden mezclarse. Esa es la razón por la que los repositorios externos, servidores MCP, herramientas conectadas y resultados obtenidos desde Internet deben tratarse como entradas no confiables.

También hay archivos que merecen una categoría especial: reglas persistentes del agente, configuraciones MCP, workflows de CI/CD, Dockerfiles, scripts de instalación y manifiestos de dependencias. Un cambio pequeño en cualquiera de ellos puede ampliar enormemente lo que el agente o la aplicación pueden hacer.

No ejecutes agentes autónomos con más privilegios de los que necesita la tarea. El principio de mínimo privilegio también se aplica al entorno de desarrollo.

Dependencias, paquetes alucinados y cadena de suministro

Una peculiaridad del código generado por modelos es que una dependencia sugerida no siempre existe. El nombre puede sonar perfectamente legítimo y, aun así, ser una alucinación. Esto abre un vector conocido como slopsquatting: registrar nombres inventados que los modelos tienden a recomendar y esperar a que alguien los instale sin verificar.

1. El modelo recomienda un paquete plausible
secure-fastapi-auth

2. El paquete no existe

3. Un atacante registra el nombre

4. Otra sesión de IA vuelve a recomendarlo

5. El desarrollador lo instala confiando en la sugerencia

La defensa no es complicada, pero debe ser obligatoria: verificar que el proyecto existe, que es el oficial, que su historial es razonable y que la versión solicitada corresponde con una publicación legítima.

Además, una dependencia real tampoco es automáticamente segura. Sigue siendo necesario controlar versiones, lockfiles, scripts de instalación, vulnerabilidades conocidas y cambios inesperados en el árbol de paquetes.


Qué nos enseñan los incidentes reales

Los incidentes documentados alrededor de herramientas y aplicaciones de vibe coding muestran dos clases de riesgo diferentes.

Aplicaciones generadas con controles insuficientes

Se han documentado casos de aplicaciones creadas con plataformas de generación rápida en las que las políticas de acceso a datos no reflejaban correctamente la intención del desarrollador. El debate sobre quién debe asumir la responsabilidad —la plataforma que genera la aplicación o la persona que la despliega— no cambia la lección técnica: una interfaz que funciona no demuestra que la capa de datos esté bien protegida.

También se han producido incidentes relacionados con la visibilidad de proyectos públicos, código fuente y conversaciones mantenidas con asistentes. Esto recuerda que el historial de prompts puede revelar arquitectura, nombres internos, decisiones de negocio y otra información que no debería considerarse automáticamente pública.

Herramientas de programación como objetivo

El NVD ya recoge vulnerabilidades en entornos de programación asistida relacionadas con prompt injection, ejecución automática, modificación de archivos y restricciones insuficientes sobre operaciones de shell. Lo importante no es memorizar cada CVE, sino entender el patrón: cuando un modelo puede actuar sobre el sistema, una instrucción manipulada deja de ser solo texto.

La seguridad del vibe coding tiene, por tanto, dos preguntas:

1. ¿Es seguro el software que genera el agente?

2. ¿Es seguro el entorno desde el que el agente trabaja?

Cómo usar IA para programar sin eliminar los controles

La IA no tiene por qué desaparecer del proceso de desarrollo. Lo razonable es impedir que su velocidad elimine los controles que ya sabemos que funcionan.

  • Define requisitos de seguridad antes de generar: autenticación, autorización, roles, propiedad de objetos, validación y restricciones de negocio deben formar parte de la especificación.
  • Trata el código generado como código de un tercero: si nadie puede explicar qué hace, todavía no está listo para producción.
  • Verifica cada dependencia: existencia, procedencia, versión, historial y scripts de instalación.
  • Ejecuta SAST, SCA y secret scanning: el código de IA debe pasar los mismos controles que cualquier otro cambio.
  • Aísla los agentes autónomos: usa entornos efímeros, credenciales temporales y permisos mínimos.
  • Protege los archivos sensibles: workflows, reglas del agente, MCP, Dockerfiles y configuración de despliegue deberían requerir revisión explícita.
  • Añade pruebas negativas: no compruebes solo que una operación funciona; comprueba que usuarios, roles y objetos incorrectos son rechazados.

También conviene separar responsabilidades. El mismo agente que escribió una funcionalidad no debería ser la única fuente que decide si esa funcionalidad es segura. Las comprobaciones importantes necesitan independencia.


Cómo auditar una aplicación generada con IA

Desde seguridad ofensiva, una aplicación creada con IA se audita con las mismas bases que cualquier otra, pero hay algunos puntos especialmente rentables.

  1. Reconstruye las fronteras de confianza. Identifica frontend, backend, base de datos, almacenamiento, APIs, webhooks y servicios externos.
  2. Prueba autorización con varias identidades. Usuario A contra objetos de usuario B, roles inferiores contra funciones administrativas y organizaciones cruzadas.
  3. Busca confianza en el frontend. Repite directamente las peticiones que la interfaz oculta.
  4. Revisa la capa de datos. RLS, reglas de acceso, buckets e IAM pueden ser la verdadera frontera de seguridad.
  5. Localiza funciones que consumen URLs o rutas. Son puntos naturales para SSRF y traversal.
  6. Analiza secretos y configuración. Repositorio, historial, bundles, logs y archivos de entorno.
  7. Audita dependencias y CI/CD. Revisa cambios en lockfiles, scripts, workflows y configuraciones del agente.
  8. Prueba estados inesperados. Repeticiones, parámetros ocultos, identificadores manipulados, transiciones imposibles y llamadas directas al backend.

La idea es sencilla: el agente suele construir muy bien el camino feliz. El pentester obtiene valor explorando todos los caminos que nadie incluyó en el prompt.


Qué significa para seguridad ofensiva

Cuanto más barato sea producir software, más importante será saber qué software merece confianza. La IA puede acelerar la implementación, pero no elimina la necesidad de comprender identidades, permisos, datos, protocolos y fronteras de confianza.

Eso mantiene vigentes habilidades muy clásicas de seguridad ofensiva: leer código, seguir flujos de datos, analizar autenticación, detectar IDOR, revisar APIs, buscar inyecciones y entender la lógica de negocio.

Lo que cambia es el contexto. Además del código, ahora interesa entender qué decisiones tomó el agente, qué información recibió, qué herramientas tenía disponibles y qué archivos modificó durante la sesión.

Si entrenas ese razonamiento con el curso Web eXploitation Expert (WXE), las mismas técnicas utilizadas para auditar aplicaciones tradicionales sirven para revisar software generado con IA: autenticación, autorización, inyecciones, SSRF, lógica de negocio, APIs y exposición de información.

¿Quieres aprender a encontrar los fallos que la IA no detecta?

En SixHack Academy entrenamos el razonamiento necesario para analizar aplicaciones reales más allá de lo que detecta un escáner. El curso Web eXploitation Expert (WXE) desarrolla esa capacidad de identificar, validar y explotar vulnerabilidades web independientemente de quién haya escrito el código.


Preguntas frecuentes

¿Es inseguro todo el código generado por IA?

No. El problema es asumir que una salida es segura porque compila o porque la funcionalidad parece correcta. La seguridad necesita validación adicional, especialmente en autorización, entradas, secretos, configuración y dependencias.

¿Usar un asistente de IA es lo mismo que hacer vibe coding?

No. Puedes utilizar IA como apoyo y mantener diseño, revisión y pruebas tradicionales. El riesgo aumenta cuando se delegan decisiones importantes y se acepta código que nadie entiende o revisa en profundidad.

¿Basta con pedirle al modelo que programe de forma segura?

No. Es útil incluir requisitos de seguridad en el prompt, pero sigue siendo necesario verificar el resultado con pruebas, análisis automático y revisión independiente.

¿Qué es el slopsquatting?

Es un ataque que aprovecha nombres de paquetes inventados por modelos de IA. Un atacante puede registrar uno de esos nombres y esperar a que alguien instale la dependencia sugerida sin comprobarla.

¿Un SAST detectará todos estos problemas?

No. Es muy útil para determinadas clases de vulnerabilidad, pero tiene limitaciones frente a autorización, lógica de negocio, arquitectura y configuraciones cuyo riesgo depende del contexto.

¿Los agentes de programación pueden ser atacados?

Sí. Si leen contenido externo y además pueden ejecutar comandos o modificar archivos, una inyección de instrucciones puede convertirse en una acción real. Por eso sus permisos y herramientas forman parte del modelo de amenazas.


Referencias

← Volver a Artículos