
Una única solicitud POST no autenticada a la API de administración de Bifrost inició un comando como el usuario de la puerta de enlace
- OrcaNUEVOOrcaCyber: GLM 5.3 Flash Abliterated2026-10-2795 tok/s
- OrcaNUEVOOrcaCyber: Qwen3.8 Flash Next Abliterated2026-10-26$0.80 / $1.60 por 1M de tokens · 249 tok/s
- OrcaNUEVOOrcaCyber: MiMo V2.6 Flash Abliterated2026-10-26$0.80 / $1.60 por 1M de tokens · 86 tok/s
- MoonshotNUEVOMoonshotAI: Kimi K3.1 Pro2026-10-2455Inteligencia
- OrcaNUEVOOrcaCyber: DeepSeek V4.1 Flash Abliterated2026-10-23$0.80 / $1.60 por 1M de tokens · 109 tok/s
- minimaxNUEVOMiniMax: M3.1 Flash2026-10-1943Inteligencia
- OrcaNUEVOOrca: OrcaCyber Ultra 1.02026-10-17$5.00 / $10.00 por 1M de tokens · 51 tok/s
- deepseekNUEVODeepSeek: DeepSeek V4.1 Flash 10172026-10-1745Inteligencia
- DeepSeekNUEVODeepSeek: DeepSeek V4.1 Flash2026-10-1740Inteligencia
- OrcaOrca: OrcaCyber Zero 1.52026-10-10$3.00 / $7.50 por 1M de tokens · 114 tok/s
- openaiOpenAI: GPT-6.1 Sol2026-09-2952Inteligencia
- anthropicAnthropic: Claude Sonnet 5.52026-09-2856Inteligencia
- typesafeTypeSafe: Jev 1.132026-09-24$0.04 / $0.00 por 1M de tokens · 120 tok/s
- OpenAIOpenAI: GPT-6 Luna2026-09-2238Inteligencia
- OpenAIOpenAI: GPT-6 Sol2026-09-2248Inteligencia
- AnthropicAnthropic: Claude Opus 5.52026-09-2258Inteligencia
- xiaomiXiaomi: MiMo-V2.6-Flash2026-09-2138Inteligencia
- xiaomiXiaomi: MiMo-V2.6-Pro2026-09-2146Inteligencia
- xAIGrok 4.72026-09-2146Inteligencia
- OrcaOrca: OrcaCyber Zero 1.02026-09-17$3.00 / $7.50 por 1M de tokens · 191 tok/s
El 14 de septiembre de 2026, JFrog Security Research publicó CVE-2026-90898, una falla de ejecución de comandos en Bifrost —la puerta de enlace de IA de código abierto mantenida por Maxim— y le asignó una puntuación de 9,8 sobre 10. El ataque fue una sola solicitud HTTP. Una solicitud POST /api/mcp/client no autenticada registra un cliente MCP stdio, que Bifrost interpreta como un nombre de programa más una lista de argumentos y lo inicia de inmediato, antes de cualquier handshake MCP, como el usuario que ejecuta la puerta de enlace; en la imagen oficial, ese usuario es appuser. Una puerta de enlace también es donde viven las claves de proveedor y las claves virtuales de un operador, por lo que un proceso que se ejecute allí llega a las credenciales. Lo que hacía anónima la solicitud era un valor predeterminado incluido de fábrica: governance.auth_config.is_enabled es false y, en palabras de JFrog, «con la autenticación desactivada, todo llamador es un administrador local». Ninguna fuente citada informa que la falla haya sido explotada. Las propias fuentes del registro, la calificación de gravedad y la evaluación de confianza se encuentran en el archivo de incidentes de IA, junto con las demás vulnerabilidades documentadas de puertas de enlace de IA y MCP del último año.
Bifrost es un único servicio que se sitúa entre una aplicación y los modelos de lenguaje a los que llama. Su repositorio lo describe como una puerta de enlace de código abierto con licencia Apache-2.0 que "unifica el acceso a 23+ proveedores ... mediante una única API compatible con OpenAI", con proxy MCP, claves virtuales, presupuestos y equilibrio de carga por proveedor entre sus funciones, y tenía aproximadamente 9.150 estrellas en GitHub el 28 de octubre de 2026. Esa combinación es exactamente la razón por la que una shell en este host en particular merece una puntuación crítica: el proceso que enruta las solicitudes es también el proceso que guarda las credenciales de cada upstream al que enruta. The Hacker News, al informar del fallo el 22 de septiembre, expuso la consecuencia sin rodeos: como la puerta de enlace almacena claves de API de cada proveedor conectado, ejecutar comandos en el proceso de la puerta de enlace otorga al atacante acceso a esas credenciales.
Todo el ataque fue un solo POST
El aviso de JFrog, publicado con la referencia JFSA-2026-001686326, describe un endpoint que existe para permitir a un administrador añadir un servidor MCP. Un cliente stdio en la especificación MCP no es una URL; es un comando y sus argumentos, que el programa anfitrión debe ejecutar. Bifrost acepta esa configuración a través de la API de administración e inicia el programa en cuanto se añade el cliente. No tiene que completarse primero ninguna negociación de capacidades, ninguna comprobación de identidad del servidor ni ningún handshake; el aviso es explícito en que el handshake no es lo que inicia el proceso.
La prueba de concepto del aviso es un cuerpo JSON corto enviado a una puerta de enlace con la autenticación dejada en su valor predeterminado. Registra un cliente cuyo comando es /bin/sh y cuyos argumentos escriben un archivo marcador, y luego vuelve a leer el marcador. JFrog añade un detalle operativo que importa durante la respuesta a incidentes: la solicitud HTTP puede expirar mientras Bifrost espera un handshake que nunca llega, y un tiempo de espera agotado en los registros no significa que el comando no se haya iniciado. Para ese momento, el proceso ya se está ejecutando.
El registro de CVE, asignado por JFrog como Autoridad de Numeración de CVE, asigna el defecto a CWE-306, falta de autenticación para una función crítica, y CWE-284, control de acceso inadecuado, y nombra los dos archivos que contienen el controlador y su middleware: transports/bifrost-http/handlers/mcp.go y transports/bifrost-http/handlers/middlewares.go. El módulo afectado es github.com/maximhq/bifrost/transports, en Linux y macOS, para todas las versiones anteriores a la 2.1.0.
El valor predeterminado que hizo anónima la solicitud
Nada de eso sería explotable sin una segunda condición, y la segunda condición es el propio valor predeterminado del producto. El middleware de autenticación de administración de Bifrost está condicionado por governance.auth_config.is_enabled, que se entrega como false. Con esa opción desactivada, el middleware trata a cada solicitante como administrador local —el propio resumen del aviso es que, con la autenticación desactivada, cada solicitante es un administrador local—, por lo que la comprobación que habría detenido la solicitud nunca estuvo en la ruta.
La corrección, el pull request #6757, se fusionó en el proyecto el 2 de septiembre de 2026, doce días antes de que se publicara la CVE y seis días antes de la versión que la incluye. Su descripción es inusualmente franca sobre la forma del problema: el pull request cierra dos primitivas de acceso no autenticado en la misma API de registro, no una. La primera es el cliente stdio. La segunda es un cliente MCP http o sse apuntado a una dirección de loopback o de red privada, que la solicitud denomina una primitiva SSRF contra servicios internos, «incluido el endpoint de metadatos en la nube 169.254.169.254». Ahora ambas se rechazan con HTTP 403 cuando la solicitud llega al controlador sin una comprobación real de credenciales. Los administradores autenticados conservan ambas capacidades, y los operadores todavía pueden aprovisionar clientes stdio mediante config.json.
Esa segunda primitiva no aparece en el texto de la CVE. Está en el parche, y es la razón por la que la corrección es una barrera en lugar de una eliminación: la funcionalidad nunca fue el error. Tratar a un llamador no autenticado como administrador sí lo era.
Dónde estaba escuchando realmente la API de administración
La alcanzabilidad es la parte del registro que las fuentes describen con mayor consistencia y miden menos. El aviso de JFrog indica que el valor predeterminado del binario estándar es localhost:8080, lo que confina a un atacante al propio host. El aviso del mismo equipo para el fallo complementario afirma que la imagen oficial de Docker se vincula a 0.0.0.0 en su lugar, y The Hacker News lo repite: la imagen hace que la API de administración sea accesible desde fuera del contenedor si se publica el puerto. El inicio rápido del propio README de Bifrost ejecuta «docker run -p 8080:8080 maximhq/bifrost», y la opción -p de Docker publica un puerto del contenedor en todas las interfaces del host a menos que se especifique una dirección. El aviso de GitHub sobre el fallo registra que la ruta reportada se verificó con la imagen publicada maximhq/bifrost:latest, donde una solicitud no autenticada lanzó /bin/sh y escribió un marcador como appuser.
Lo que ninguna fuente proporciona es una cifra. No hay un recuento de instancias de Bifrost expuestas a internet, ni resultados de escaneos, ni telemetría, ni víctimas. El registro no refleja ningún daño real, y esa ausencia es un dato sobre la información publicada más que una garantía tranquilizadora: la clase de vulnerabilidad solo es peligrosa cuando coinciden dos condiciones, un servicio a la escucha expuesto y un valor predeterminado sin modificar, y nadie ha publicado con qué frecuencia coincidieron.
Un endpoint, dos fallos, una causa raíz
Ocho días antes del aviso de MCP, el 6 de septiembre de 2026, el mismo equipo de investigación publicó CVE-2026-86242, una segunda vía no autenticada hacia el mismo proceso. Descubierta por Or Peles y con una puntuación de 8.1, aprovecha POST /api/plugins: Bifrost acepta un plugin personalizado habilitado cuya ruta es una URL HTTP, el cargador de objetos compartidos trata una ruta con prefijo http como una descarga, escribe el cuerpo en un archivo .so temporal y entrega ese archivo a plugin.Open de Go. Si la carga se realiza correctamente, una función Init opcional se ejecuta inmediatamente con la configuración del atacante, como el usuario de la puerta de enlace.
La variante de compilación determina qué obtiene un atacante. En las compilaciones enlazadas dinámicamente que el proyecto documenta para plugins de Go personalizados, se espera que la carga tenga éxito, lo que el aviso denomina ejecución remota de código no autenticada. En la imagen Docker enlazada estáticamente publicada, plugin.Open falla con "Dynamic loading not supported", por lo que la misma solicitud se degrada a falsificación de solicitud del lado del servidor. Un plugin cargable también debe coincidir con la versión de Go, el sistema operativo, la arquitectura y el tipo de enlace del host, lo cual es una restricción real y no una formalidad. La corrección es transports/v2.0.0, mediante la pull request #5763, y el rango afectado es todo lo anterior a ella.
La trampa está en el orden de publicación. v2.0.0 corrige la ruta del plugin y no corrige la ruta de MCP; The Hacker News lo dice explícitamente, y el aviso de MCP de JFrog confirma que v2.0.0 todavía permite el registro stdio sin autenticación. Un operador que aplicó el parche con prontitud tras el aviso del 6 de septiembre seguía expuesto, solo por ese punto, hasta que se publicó transports/v2.1.0 el 8 de septiembre. Ambos fallos se reducen a la misma frase en ambos avisos y en la propia pull request del proveedor: la autenticación deshabilitada es la configuración predeterminada.
Lo que las fuentes establecen y lo que no
El mecanismo, el rango de versiones, la corrección y el reconocimiento coinciden en el aviso de seguridad, el registro CVE que asignó JFrog, la solicitud de incorporación de cambios y las notas de la versión del propio proyecto, y The Hacker News. La discrepancia restante es sobre la gravedad, y es real.
El 9,8 es la puntuación de JFrog como CNA asignante, y es la puntuación que mantiene NVD: el registro de NVD incluye reefs@jfrog.com como fuente de la métrica y, a fecha de 28 de octubre de 2026, sigue mostrando la entrada en estado «Awaiting Analysis», lo que significa que NVD ha publicado el vector del asignador en lugar de su propio análisis. La evaluación SSVC del Coordinador de CISA adjunta al mismo registro, con marca temporal de 14 de septiembre de 2026, indica explotación «none», automatizable «yes» e impacto técnico «total». El modelo EPSS de FIRST situó la probabilidad de explotación en los próximos 30 días en 2,3 por ciento el 27 de octubre de 2026, en el percentil 83 entre todas las CVE puntuadas, y ni esta CVE ni CVE-2026-86242 aparecen en el catálogo Known Exploited Vulnerabilities de CISA con fecha de 27 de octubre de 2026.
Frente a ello, Maxim cuestiona la calificación. En una declaración a The Hacker News, Akshay Deo, director de tecnología y cofundador de la empresa, afirmó que el riesgo práctico es menor de lo que sugiere la puntuación crítica, porque la explotación requiere que se pueda acceder a la interfaz de gestión desde una red no confiable y que el operador haya dejado la autenticación sin configurar; la implementación predeterminada y documentada, dijo, coloca la puerta de enlace dentro de una red privada. The Hacker News informa que Maxim considera que la falla es de baja gravedad y está trabajando con JFrog, que asignó el CVE, para revisar la evaluación. Esa declaración aparece en ese único medio; no se encontró ninguna otra publicación que citara la postura de Maxim, y no se había publicado ninguna revisión hasta el 28 de octubre de 2026 —el registro CVE se actualizó por última vez el 14 de septiembre y la entrada de NVD el 18 de septiembre, ambos todavía en 9.8.
Hay otros dos vacíos que merecen nombrarse en lugar de disimularlos. Los avisos de GitHub del proyecto, publicados el 23 de septiembre de 2026 y que acreditan al investigador de JFrog como informante, siguen otorgando 9.8 al fallo de MCP y 8.1 al fallo del complemento, sin rastro de la revisión que describió Maxim. Y los rangos afectados de esos avisos están expresados en función de versiones de módulo de Go —inferiores a 1.5.27 e inferiores a 1.6.3— en lugar de las etiquetas de versión de transports que utilizan los avisos de JFrog, así que un operador que coteje un documento con el otro tiene que conciliar dos esquemas de numeración antes de decidir si una compilación se ve afectada.

Qué cambió y qué se les dijo a los operadores que hicieran
La cronología va hacia atrás desde la divulgación, que es la parte menos intuitiva del registro. La pull request #6757 se fusionó el 2 de septiembre de 2026. transports/v2.1.0, la versión que el aviso señala como la primera que contiene la corrección, se publicó el 8 de septiembre — seis días antes de que CVE-2026-90898 se publicara el 14 de septiembre. La corrección del plugin del proyecto precedió a su propio aviso de la misma manera: transports/v2.0.0 se lanzó el 26 de agosto, once días antes del CVE del 6 de septiembre. Los operadores que siguen las versiones en lugar de los feeds tenían los parches antes de tener las advertencias.
Lo que ofrece la actualización es acotado y específico. En 2.1.0 y versiones posteriores, un registro stdio no autenticado devuelve 403 y el comando no se inicia; los administradores autenticados conservan la capacidad y el aprovisionamiento mediante config.json sigue funcionando. La medida provisional del aviso para quienes no puedan actualizar es establecer governance.auth_config.is_enabled en true, usar credenciales de administrador robustas y mantener el listener de administración fuera de redes no confiables. La instrucción de JFrog para las instancias que se ejecutaron expuestas con la autenticación deshabilitada no es investigar y esperar que todo esté bien: hay que tratarlas como comprometidas y rotar las claves virtuales y las credenciales del proveedor.
La aritmética de versiones es la parte que más probablemente se malinterprete. v2.0.0 no corrige este defecto. La línea 1.6.x hasta 1.6.11 tampoco contiene la corrección, y la etiqueta más reciente de la serie 1.6 del proyecto es transports/v1.6.11, publicada el 14 de agosto de 2026, sin ninguna línea 1.7 en el repositorio a fecha de 28 de octubre de 2026 — por lo que no hay ninguna versión parcheada dentro de esa serie, y un operador de 1.6.x tiene que pasar a 2.1.0 o posterior en lugar de esperar un backport. La línea de versión actual está muy por delante de ese punto: transports/v2.3.2 se publicó el 20 de octubre de 2026.

Después de la publicación ocurrieron dos cosas que un defensor puede aprovechar. Los avisos de seguridad de GitHub del proyecto —GHSA-86gf-xh3g-rvxq para la falla de MCP, de gravedad crítica, y GHSA-2qp8-4xgm-fw6g para la falla del plugin, de gravedad alta— se publicaron el 23 de septiembre de 2026, lo que da a los feeds de dependencias y de avisos un segundo identificador con el que hacer coincidencias. Y el 13 de octubre de 2026 se integró una plantilla de detección para CVE-2026-90898 en el repositorio público nuclei-templates, lo que significa que la comprobación de un intento de registro no autenticado ahora es algo que un pipeline de escaneo puede ejecutar, en lugar de algo que cada equipo tiene que escribir.

Lo que queda abierto es la gravedad, y se resolverá o no por las dos organizaciones que todavía siguen hablando del asunto. La posición de Maxim, según lo informado, es que un 9.8 sobreestima una falla que necesita un listener expuesto y un valor predeterminado sin configurar para tener relevancia — una afirmación que es comprobable en principio y no se ha probado en público, porque nadie ha publicado cuántas implementaciones cumplían esas dos condiciones. La posición de JFrog es la puntuación que asignó como CNA, que sigue vigente en el registro CVE y en el NVD. Hasta que uno de ellos publique una revisión, la lectura operativa es la misma en cualquier caso: la falla es real y se verificó de extremo a extremo en la imagen de contenedor publicada, la corrección se publicó antes de la advertencia, la serie 1.6 no tiene ninguna corrección, y cualquier instancia que se haya ejecutado con la autenticación deshabilitada en un listener accesible debe tratarse como un incidente de credenciales en lugar de un parche para programar.
