El problema de seguridad del vibe coding no es que los agentes escriban código inseguro a propósito. Es que escriben código plausible rápido, y el código plausible pasa el único test que casi todo el vibe coding aplica: arranca. Los agujeros de seguridad no impiden que una app arranque. Se quedan ahí en silencio hasta que alguien los encuentra, y ese alguien rara vez eres tú.
Quiero ser preciso, no alarmista. Tu app de fin de semana probablemente no esté siendo atacada activamente. Pero en cuanto guarda datos de un usuario real o cobra un pago real, la distancia entre “funciona” y “es seguro operarla” pasa a ser tu problema, y esa distancia tiene una forma predecible. El código generado que nadie revisó tiende a filtrar por los mismos tres sitios. Déjame recorrer cada uno, con el mecanismo, para que lo cierres en vez de preocuparte por él.
Agujero 1: secretos en el código
El más común y el más fácil de arreglar. Le pides a un agente que conecte con una base de datos, un servicio de email, una pasarela de pago. Escribe código que funciona, y para que funcione mete la API key ahí mismo, en el código fuente. A veces la deja fija en un archivo de configuración. A veces commitea tu .env porque nada le dijo que no.
El mecanismo es simple: el agente optimiza para que el código arranque ahora, y una clave literal arranca. Una clave leída de una variable de entorno también arranca, pero pide un segundo paso que el agente no tiene motivo para priorizar salvo que se lo pidas. Así que toma el atajo, y el atajo acaba en tu historial de git, donde se queda incluso después de borrar la línea.
Cerrarlo es mecánico. Saca cada credencial del código y llévala a variables de entorno o a un gestor de secretos. Añade los archivos de secretos al .gitignore antes del primer commit, no después. Si una clave llegó a tocar un commit, rótala, porque git recuerda. Y revisa el historial, porque la clave que dejaste fija la primera semana sigue en el log que olvidaste.
Agujero 2: entrada que nadie validó
Este es el caro, y el que un agente tiene menos probabilidades de manejar sin que se lo pidas.
Cada sitio donde tu app acepta entrada de fuera es un sitio donde algo puede salir mal: un campo de formulario, un parámetro de URL, un archivo subido, el cuerpo de una petición. El código seguro trata todo eso como hostil hasta que se demuestre lo contrario. El código generado suele tratarlo como bien formado, porque el camino feliz es lo que describía el prompt. El agente construyó la feature que pediste. No le pediste que asumiera que el usuario es un atacante, así que no lo hizo.
El resultado es que todo el OWASP Top 10 se lee como una lista de cosas que tu app probablemente hace mal: inyección porque una consulta se armó concatenando una cadena que controla el usuario, control de acceso roto porque un endpoint comprueba que has iniciado sesión pero no que el registro sea tuyo, exposición de datos porque un manejador de errores devuelve la traza completa. Ninguna rompe la app. Todas son puertas.
El arreglo no es glamuroso y no es opcional. Valida y sanea la entrada en la frontera, siguiendo algo concreto como la guía de validación de entrada de OWASP en vez de tu intuición. Usa consultas parametrizadas para que la entrada del usuario nunca se concatene dentro de un comando. Comprueba la autorización sobre el registro, no solo sobre la sesión. Son patrones que un agente aplica bien en cuanto los conviertes en parte del contrato, y se salta por completo cuando no.
Agujero 3: dependencias que nadie auditó
Un agente recurre a librerías como tú recurrirías a un resultado de búsqueda. Elige un paquete que resuelve el problema, lo añade a tu manifiesto y sigue. No comprueba si el paquete se mantiene, si tiene vulnerabilidades conocidas ni si es siquiera el paquete que crees que es.
Ese último punto importa más de lo que suena. Los atacantes publican paquetes con nombres parecidos a los populares, apostando a un error de tecleo o a un autocompletado seguro de sí mismo. Un agente generando una lista de dependencias de memoria es justo el tipo de autocompletado seguro al que apuestan. Puedes acabar importando algo que nadie auditó al núcleo de tu app, y llegó porque un modelo lo sugirió y tú no miraste.
El arreglo es poner una puerta entre “se añadió una dependencia” y “la dependencia se publica”. Escanea tu árbol de dependencias en busca de vulnerabilidades conocidas, y hazlo de forma continua, porque un paquete que estaba limpio cuando el agente lo añadió puede descubrirse vulnerable el mes que viene. Es exactamente la práctica sobre la que escribí en asegurar el código de IA con Snyk: la capa de dependencias es donde el código generado hereda los errores de otra gente, y la única defensa es comprobar en vez de confiar.
Por qué lo que se rompió fue la revisión
Fíjate en lo que comparten los tres agujeros. Ninguno es exótico. Un desarrollador leyendo el código pillaría la clave fija, cuestionaría el formulario sin validar y levantaría una ceja ante la dependencia desconocida. Los agujeros existen porque nadie leyó el código, y nadie lo leyó porque el atractivo entero del vibe coding es no tener que hacerlo.
Esa es la tensión real. La velocidad viene de saltarse la revisión, y la seguridad viene de la revisión. No puedes quedarte con la velocidad y borrar el riesgo. Lo que sí puedes es mover la revisión de “lee cada línea” a “comprueba las tres cosas que de verdad filtran”, que es un trabajo mucho más pequeño.
Aquí también aparece, del modo más nítido posible, la línea entre vibe coding e ingeniería asistida por IA. El vibe coding confía en el output porque arranca. La ingeniería trata la seguridad como parte de la definición de hecho, y se niega a dar una feature por terminada hasta que la frontera está validada, los secretos están fuera del código y las dependencias están limpias. Mismo agente, misma velocidad, distinto contrato.
El marco de la deuda, aplicado a la seguridad
Los agujeros sin cerrar son un tipo concreto de deuda del vibe coding, y se comportan como la peor: barata de cargar, catastrófica de saldar. Una validación de entrada que falta no cuesta nada hasta el día en que lo cuesta todo, y a diferencia de una feature lenta, no recibes aviso de que llega la factura. Otro te programa el pago.
Por eso la seguridad no es algo que atornillas al final del camino del vibe coding a producción. Es una de las puertas que definen si tienes un producto o una responsabilidad legal con una UI bonita.
Dónde encaja PaellaDoc
La razón de que estos agujeros sobrevivan es que “¿comprobamos los secretos, la entrada, las dependencias?” es una pregunta que nadie escribió, así que nadie respondió. La comprobación vive en la cabeza de una persona, y las cabezas olvidan, sobre todo cuando el agente fue más rápido que quien revisa.
PaellaDoc convierte esas comprobaciones en parte del contrato de un cambio y guarda la evidencia de que se ejecutaron, unida al código que cubren, en vez de depender de que te acuerdes. La idea no es frenar al agente. Es asegurar que cuando un cambio se cierra, las preguntas de seguridad aburridas y que sostienen peso tienen respuestas reales en registro, no la suposición de que el código estaba bien porque arrancó.
Preguntas frecuentes
¿El software hecho con vibe coding es inseguro por naturaleza? No. Está sin revisar, que es distinto. El mismo agente escribe código seguro cuando la seguridad es parte del contrato, y código con fugas cuando el único requisito es que arranque. El riesgo viene de saltarse la revisión, no del modelo.
¿Qué es lo más importante que comprobar primero? Los secretos. Asegúrate de que ninguna API key ni credencial vive en tu código o en el historial de git, porque ese agujero es el más fácil de explotar y el más fácil de cerrar. Luego pasa a la validación de entrada y a las dependencias.
¿Necesito un experto en seguridad para arreglar esto? Para la mayoría de apps de vibe coding, no. Sacar los secretos del código, validar la entrada en la frontera con una guía establecida y escanear tus dependencias cierra los agujeros comunes. Un especialista importa cuando manejas datos sensibles a escala, no el día uno.