La seguridad de la cadena de suministro de software es un problema conocido, con prácticas razonablemente maduras: inventario de componentes, análisis de dependencias, firma de artefactos, fijación de versiones. La adopción de IA no inventa un problema nuevo, pero introduce tres vectores que la mayoría de esos controles no cubre, porque fueron diseñados para un mundo donde lo que entraba al repositorio era código escrito por alguien y paquetes publicados por alguien.
Los tres tienen algo en común que conviene nombrar desde el principio: en ninguno hace falta vulnerar un sistema. El atacante aprovecha decisiones ordinarias del equipo de desarrollo — descargar un modelo, aceptar una sugerencia, instalar una dependencia — que hoy no pasan por ninguna puerta de control.
Modelos y pesos descargados de repositorios públicos
Un archivo de pesos de modelo es un artefacto binario de cientos de megabytes o varios gigabytes que entra a tu infraestructura, se carga en un proceso con permisos y ejecuta cálculo. Tratado con el mismo criterio que un paquete de software, exigiría procedencia verificada, firma y revisión. En la práctica se descarga con una línea de código desde un repositorio público, muchas veces sin fijar una revisión concreta, y llega a producción sin que ningún proceso de seguridad lo haya visto.
El riesgo más directo es de ejecución. Varios formatos históricos de serialización de modelos permiten, por diseño del formato subyacente, ejecutar código arbitrario en el momento de la carga. Cargar un modelo desde una fuente no verificada equivale entonces a ejecutar un binario descargado de internet, con la diferencia de que nadie lo percibe así porque la operación parece un cálculo, no una instalación. Los formatos modernos pensados para almacenar solo tensores reducen mucho este problema, y migrar a ellos es una de las mejoras con mejor relación entre esfuerzo y riesgo evitado.
El segundo riesgo es de comportamiento, y es más difícil de detectar. Un modelo puede haber sido ajustado para responder de forma alterada ante condiciones específicas sin que su desempeño general muestre nada anómalo. Es la lógica del envenenamiento de datos aplicada al artefacto final: ninguna prueba de precisión agregada revela un comportamiento que solo se activa con una entrada concreta.
Los controles razonables son los mismos que aplicas a cualquier dependencia binaria. Fija la revisión exacta del artefacto y verifica su resumen criptográfico en cada despliegue, en lugar de apuntar a una etiqueta móvil. Mantén una copia interna de los modelos aprobados, de modo que producción nunca dependa de la disponibilidad ni de la integridad de un repositorio externo. Carga los modelos en un entorno con permisos mínimos y sin acceso de red saliente durante la carga. Y registra en tu inventario de componentes qué modelos usa cada sistema, con su origen y su versión, porque el día que se reporte un problema en uno de ellos la pregunta será cuáles de tus servicios lo tienen.
Un archivo de pesos es una dependencia ejecutable. Si no lo tratas como tal en tu proceso de compilación, tienes un binario sin revisar en producción.
Código generado que arrastra dependencias inseguras
Los asistentes de programación proponen soluciones completas, y una solución completa incluye sus importaciones. Ahí se cuelan dos problemas distintos.
El primero es de versiones y patrones antiguos. Un modelo aprende de un corpus con años de código público, donde conviven la forma correcta actual y la forma que era correcta hace seis años. La sugerencia puede traer una biblioteca abandonada, una versión con vulnerabilidades conocidas, o un patrón criptográfico obsoleto que ya nadie recomienda pero que aparece miles de veces en el material de entrenamiento. Nada de esto se ve al revisar la lógica de la función, que suele estar bien.
El segundo es de volumen y atención. La revisión de código funciona porque quien revisa tiene una expectativa razonable sobre lo que va a encontrar. Cuando el volumen de líneas propuestas crece varias veces y todas llegan con formato limpio, comentarios coherentes y aspecto competente, la revisión se desplaza sin que nadie lo decida: se verifica que el código haga lo que dice, no que no haga nada más ni que sus dependencias sean sanas. La sugerencia correcta no es revisar más, que no escala, sino mover la verificación a controles automáticos que no dependen de la atención humana.
En concreto: análisis de composición de software obligatorio en cada solicitud de cambio, con bloqueo cuando aparece una dependencia nueva no aprobada; una política explícita de que toda dependencia introducida por código generado requiere justificación en la descripción del cambio; y análisis estático orientado a patrones de seguridad, no solo a errores de estilo. Ninguno de estos controles es nuevo. Lo nuevo es que ahora son indispensables, porque el volumen de código que entra ya no está limitado por la velocidad de escritura de una persona.
Paquetes alucinados y el registro anticipado
El tercer vector es el más específico de esta tecnología y el que menos equipos tienen en su modelo de amenazas. Un modelo puede sugerir con total naturalidad la importación de un paquete que no existe: un nombre plausible, coherente con la convención de nomenclatura del ecosistema, que encaja con lo que el desarrollador esperaba encontrar. El programador ejecuta el gestor de paquetes, obtiene un error de paquete inexistente, y normalmente ahí termina la historia.
El ataque consiste en que no termine ahí. Un atacante puede consultar sistemáticamente a los modelos disponibles, recopilar los nombres inexistentes que sugieren con frecuencia, y registrar esos paquetes en el repositorio público con contenido malicioso. Cuando el siguiente desarrollador reciba la misma sugerencia y ejecute la instalación, el paquete ya existirá. No hay error, no hay señal de alerta, y el código malicioso se ejecuta en el equipo de desarrollo con las credenciales que ese equipo tenga a mano —que suelen ser bastantes.
Lo que hace peligroso este vector es que invierte la señal de seguridad habitual. El fallo de instalación es una advertencia útil; su desaparición es el momento del compromiso. Además, la tendencia de un modelo a sugerir un nombre inexistente es reproducible: el atacante no necesita adivinar a quién apuntar, sino esperar a que alguien haga la pregunta correcta.
Las defensas efectivas son de gobierno del ecosistema de paquetes. Usa un repositorio interno que actúe como intermediario y sirva solo paquetes aprobados, en lugar de permitir la instalación directa desde el registro público. Exige archivos de bloqueo con resúmenes criptográficos, de modo que una instalación solo pueda resolver artefactos ya conocidos. Revisa señales elementales antes de aprobar un paquete nuevo: antigüedad, número de publicaciones, mantenedores, y si su nombre se parece sospechosamente al de un proyecto conocido. Y aplica cuarentena a paquetes publicados recientemente, porque el ataque depende de que el registro sea muy nuevo.
Dónde empezar
Los tres vectores comparten la misma raíz: artefactos que entran a tu cadena de construcción sin pasar por una puerta. Por eso la primera acción no es comprar una herramienta, sino responder tres preguntas sobre lo que ya tienes. Qué modelos hay desplegados hoy, de dónde vinieron y quién los aprobó. Qué proporción del código nuevo llega asistido y qué control automático lo revisa antes de fusionarse. Y si un desarrollador puede instalar hoy, desde su equipo, un paquete publicado ayer por alguien que nadie conoce. Las tres respuestas suelen ser incómodas, y las tres se corrigen con controles que tu organización probablemente ya sabe operar para el software convencional.