Saltar al contenido

Un equipo editorial y una comunidad que crean con IA

← Vibecoding

Vibecoding · · 7 min de lectura

¿Es seguro el código generado por IA? Vibecoding y seguridad

El código generado por IA no es seguro ni inseguro: está sin verificar. Las clases de riesgo reales y una lista de verificación.

La respuesta corta a la pregunta del título: el código generado por IA no es seguro ni inseguro, está sin verificar. Un modelo de lenguaje genera lo estadísticamente más probable, no lo más seguro. La diferencia sigue siendo sutil justo hasta que tu endpoint sale a internet con una clave incrustada en el código o con una consulta SQL armada concatenando strings. El vibecoding no crea nuevas clases de vulnerabilidades. Solo las acelera, y ahí está el quid de la cuestión.

Por qué estamos hablando de esto

En los últimos dos años ha cambiado el perfil de quien lleva código a producción. Antes, “subo a prod” significaba alguien que había pasado por code reviews, conocía la diferencia entre GET y POST y entendía por qué nunca hay que fiarse de la entrada del usuario. Hoy ese mismo deploy lo hace alguien que le pidió a un agente “agrega login” y pegó el resultado. El código funciona, la demo sale bien, el cliente está contento. La vulnerabilidad es invisible porque nada está en llamas, hasta que alguien se pone a buscar.

Este no es un texto contra la IA. Escribo la mayor parte de mi código con un asistente y no volvería a un editor a secas. Pero tratar el código generado como listo para desplegar es un error de categoría. Es el primer borrador de un junior muy rápido, no una auditoría de seguridad. Lo que está en juego es real: una base de datos de clientes filtrada, una cuenta secuestrada, una multa por el RGPD. Y no se trata de si sabes programar, sino de si alguien revisó la seguridad del código antes de que saliera al mundo.

Clases de riesgo reales, no teóricas

Dejemos de lado las abstracciones. Esto es lo que realmente sale de los modelos cuando les pides “código que funcione”, ordenado según la frecuencia con la que lo veo en la práctica:

  • Secretos en el código. Claves de API, contraseñas de bases de datos, tokens: metidos directamente en un archivo “a modo de ejemplo” que luego acaba en el repositorio. El modelo no tiene ni idea de que tu ejemplo va a ir a producción. Peor aún: una vez hecho el push, el secreto se queda para siempre en el historial de Git, incluso después de borrarlo del archivo actual, y la única solución real es rotar la clave.
  • Inyección: SQL y comandos. Consultas construidas concatenando strings en lugar de parametrizarlas. "SELECT * FROM users WHERE id = " + userId es un clásico que el modelo no deja de sugerir, porque lo ha visto millones de veces en sus datos de entrenamiento.
  • XSS en el frontend. Renderizar datos del usuario sin escaparlos, dangerouslySetInnerHTML con entrada no confiable, la falta de Content-Security-Policy.
  • Dependencias inseguras. El modelo sugiere un paquete que existe pero está abandonado, que tiene una vulnerabilidad conocida o que, en el peor de los casos, no existe en absoluto, y alguien malintencionado ha registrado ese nombre en npm (typosquatting y “slopsquatting”).
  • Permisos demasiado amplios. Un bucket de S3 configurado como público, un rol de IAM con *:*, CORS abierto a *, un puerto de base de datos expuesto al mundo. “Para que funcione”, y funciona, para todo el mundo.
  • Autenticación débil. JWT sin verificación de firma, contraseñas hasheadas con MD5, sin rate limiting en el endpoint de login, sesiones que nunca caducan.

Ninguna de estas es una vulnerabilidad nueva. Todas llevan años en el OWASP Top 10. Lo nuevo es la velocidad con la que llegan a producción.

Por qué la IA agrava algunos riesgos

Hay dos mecanismos que convierten al asistente en un multiplicador del riesgo, más que en su origen.

Velocidad. Cuando escribes a mano, tienes un filtro temporal natural: cada línea cuesta segundos de reflexión. Con un agente obtienes 200 líneas en diez segundos. El volumen de código que “pasa volando” ante tu atención sin una revisión real crece un orden de magnitud. El hueco en tu proceso de revisión no es constante: escala con la velocidad a la que generas código.

Confianza. Este es el más peligroso. El código del modelo es sintácticamente perfecto: nombres de variables sensatos, comentarios, manejo de errores, todos los paréntesis cerrados. Parece código de un senior. Nuestro cerebro interpreta esa estética como señal de competencia y baja la guardia. Mientras tanto, un try/catch muy pulcro puede capturar un error y tragárselo en silencio, y una función con un nombre tan bonito como sanitizeInput puede no sanear nada. Que algo sea plausible no significa que sea correcto.

A eso se suman las alucinaciones: un modelo inventará con total seguridad un flag de configuración, un método de un SDK o un paquete que no existe. En un contexto de seguridad, eso significa que “activé el cifrado” puede ser una llamada a una opción inexistente que, en silencio, no hace nada.

Lista de verificación antes de desplegar

Antes de que el código generado llegue a producción, repasa estos puntos. No hace falta hacerlo todo a mano (casi todo se puede automatizar), pero no puedes saltarte ninguno “porque solo es un MVP”.

  1. Secretos. ¿Está el diff libre de claves, contraseñas y tokens? ¿Todo lo sensible está en variables de entorno, con .env incluido en .gitignore?
  2. Entrada del usuario. ¿Todos los datos externos (request, formulario, parámetro de URL, archivo) se validan y se parametrizan? Las consultas a la base de datos, nunca mediante concatenación.
  3. Permisos. ¿Los roles, los buckets y el CORS están reducidos al mínimo? Mínimo privilegio: todo cerrado por defecto y solo abres lo necesario.
  4. Dependencias. ¿Cada paquete nuevo existe de verdad, tiene mantenimiento y está libre de CVE conocidas? Revisa el número de descargas y la fecha de la última publicación antes de agregarlo a package.json.
  5. Autenticación y autorización. ¿Los endpoints protegidos comprueban de verdad la identidad y los permisos? La falta de control de acceso a nivel de objeto es el agujero más común en las API.
  6. Manejo de errores. ¿Hay algún catch que se trague un error en silencio? ¿Los mensajes de error evitan filtrar stack traces o datos sensibles al usuario?
  7. Comprensión. ¿Puedes explicar qué hace cada línea que no sea obvia? Si no entiendes un fragmento, no lo publicas: pedirle al modelo que te lo explique es gratis.

Herramientas que hacen este trabajo por ti

Una lista de verificación mental no escala. Por suerte, la automatización detecta la mayoría de estas clases de problemas, y debería ser una barrera obligatoria en CI, no una opción.

Escaneo de secretos. Gitleaks o TruffleHog como hook de pre-commit y como paso del pipeline. Agrega también push protection a nivel de repositorio (GitHub y GitLab la traen integrada). Es la primera línea de defensa y la más barata: un secreto que nunca llega al historial no necesita rotación.

SAST: análisis estático. Semgrep, CodeQL o Snyk Code leen el código sin ejecutarlo y señalan patrones de inyección, XSS o API inseguras. Semgrep tiene una sintaxis de reglas legible y es fácil escribir reglas propias adaptadas a tu stack.

Auditoría de dependencias. npm audit, Dependabot o Snyk: buscan vulnerabilidades conocidas en el árbol de dependencias y abren PR de actualización. Intégralo en CI con un umbral: high y critical bloquean el merge.

Escaneo de infraestructura. Si tienes Terraform o manifiestos de Kubernetes, Checkov o tfsec detectarán un bucket público y un rol de IAM demasiado amplio antes de que se aprovisione nada. Esto importa especialmente en el vibecoding, porque los modelos generan alegremente configuraciones “abiertas de par en par” solo para que todo pase; los valores por defecto seguros ya exigen una decisión humana consciente.

Importante: estas herramientas también generan falsos positivos. Su función no es sustituir el pensamiento, sino reducir la superficie que tiene que revisar un humano. Un pipeline en verde no es un certificado de seguridad: es la ausencia de problemas conocidos.

La mentalidad correcta: la IA es un junior rápido, no un auditor

El modelo mental más sano que conozco: trata al asistente como a un desarrollador junior muy capaz y muy rápido. Escribe una cantidad impresionante de código, conoce la sintaxis mejor que tú y nunca se cansa. Y, como cualquier junior, no tiene contexto sobre tu sistema, no sufre las consecuencias de un incidente y a veces afirma cosas falsas con total seguridad.

Hay dos cosas que no haces con un junior: no publicas su código sin revisarlo y no lo conviertes en revisor de su propio trabajo. Las mismas dos reglas se aplican al modelo. Puedes pedirle a la IA que señale posibles problemas de seguridad (puede ayudar como un par de ojos extra), pero eso no te exime de una verificación real. Un revisor que escribió el código tiene un punto ciego justo donde cometió el error.

La responsabilidad de la seguridad sigue siendo del humano que presiona “deploy”. No se trata de desconfiar de la herramienta, sino de quién contesta el teléfono a las tres de la mañana.

TL;DR

El código generado por IA no es seguro ni inseguro por naturaleza: está sin verificar. Los riesgos reales son los viejos conocidos: secretos en el código, inyección, XSS, dependencias inseguras, permisos demasiado amplios y fe ciega en el código que se ve bien. La IA los agrava por la velocidad y por la falsa confianza que transmite. La defensa es una lista de verificación antes de desplegar más automatización en CI: escaneo de secretos, SAST, auditoría de dependencias y escaneo de infraestructura. La mentalidad que funciona: la IA es un junior rápido, no un auditor de seguridad, y la revisión y la responsabilidad siguen siendo tuyas.

¿Es seguro el código generado por IA? Vibecoding y seguridad | vibecoding.inc