Neutron, nuestro motor de IA, obtuvo un 97.1% en el benchmark CyberGym de UC Berkeley. Más información

Análisis a fondo

Análisis a fondo

RCE en el inicio de sesión OAuth MCP de OpenCode en Windows, corregida en 1.18.33

En OpenCode 1.0.137 a 1.18.32 para Windows y WSL, la URL de inicio de sesión OAuth de un servidor MCP malicioso llega a PowerShell y ejecuta código como el desarrollador; corregido en 1.18.33, sin CVE.

Resumen

  • Durante un inicio de sesión OAuth MCP, el servidor que se autentica elige la dirección web a la que se envía el navegador del desarrollador. En OpenCode para Windows y WSL, las versiones 1.0.137 a 1.18.32 pasaban esa URL controlada por el servidor al paquete open, que construía un comando PowerShell alrededor de ella sin escaparla. Así, una dirección con una subexpresión PowerShell se ejecutaba como el desarrollador.
  • Pillar Security, que descubrió el fallo y lo comunicó de forma privada el 29 de agosto de 2026, lo califica como crítico y propone CVSS v3.1 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H), CWE-78. Es la calificación propuesta por Pillar: el ataque documentado sigue requiriendo que el desarrollador ejecute opencode mcp auth, tras lo cual el intercambio no necesita más preguntas ni consentimiento. No hay CVE ni aviso del proveedor: Anomaly, desarrollador de OpenCode, considera que un servidor MCP remoto malicioso queda fuera de su modelo de amenazas, por lo que los escáneres que cotejan versiones con avisos publicados no tienen registro de este fallo.
  • macOS y Linux no están afectados, porque allí OpenCode abre el navegador sin pasar la URL por un shell. No se han comunicado ataques mediante el fallo y Pillar no publicó indicadores de compromiso.
  • Actualice a OpenCode 1.18.33 o posterior, publicado el 28 de septiembre de 2026. Si aún no puede actualizar, elimine de la configuración de OpenCode en equipos Windows y WSL todos los servidores MCP remotos que no haya evaluado por completo.

¿Estoy afectado?

Está afectado si ejecuta opencode-ai 1.0.137–1.18.32 o @opencode/cli 2.0.0–2.0.17 en Windows o WSL con un servidor MCP remoto cuyas respuestas no controle e inicia la autenticación de ese servidor. Deben cumplirse todas estas condiciones:

  • Ejecuta OpenCode en Windows o Windows Subsystem for Linux (WSL). Las instalaciones macOS y Linux no están afectadas: el lanzador de navegador de esas plataformas nunca pasa la URL por un shell.
  • La versión es opencode-ai 1.0.137 a 1.18.32 inclusive, o @opencode/cli 2.0.0 a 2.0.17 inclusive.
  • Hay al menos un servidor MCP remoto configurado cuyas respuestas no controla por completo. No tenía que ser malicioso al configurarse: el payload llega en una respuesta HTTP al iniciar sesión, por lo que un servidor comprometido después, una entrada de registro secuestrada, un dominio de typosquatting o un dominio caducado que cambió de propietario pueden proporcionar la misma dirección.
  • El desarrollador inicia la autenticación de ese servidor ejecutando opencode mcp auth. Tener el servidor configurado o abrir una sesión no llega al paso del navegador.
Paquete Versiones afectadas Versión corregida
opencode-ai en npm, Windows y WSL 1.0.137 a 1.18.32 1.18.33 (28 de septiembre de 2026)
opencode-ai en npm, macOS y Linux no afectado no aplicable
@opencode/cli en npm, Windows y WSL 2.0.0 a 2.0.17 2.0.18 (25 de septiembre de 2026)

opencode-ai registró 2.180.172 descargas npm durante el 16–22 de octubre de 2026. Las descargas son un indicador de alcance, no un recuento de instalaciones afectadas.

Compruebe qué ejecuta y qué servidores están configurados:

opencode mcp list                               # which MCP servers are configured
npm ls -g opencode-ai @opencode/cli 2>/dev/null  # npm installs and their versions
brew list --versions opencode 2>/dev/null       # Homebrew installs

La corrección está en el árbol de código compartido del proyecto desde el 25 de septiembre de 2026, por lo que actualizar cualquiera de los dos paquetes a su versión actual elimina el fallo; la matriz de divulgación de Pillar Security cubre la rama opencode-ai.

¿Cómo lo corrijo?

Actualice opencode-ai a 1.18.33 o posterior, o @opencode/cli a 2.0.18 o posterior:

npm i -g opencode-ai@latest

Para la rama del paquete @opencode/cli:

npm i -g @opencode/cli@latest

Si aún no puede actualizar un equipo Windows o WSL:

  • Elimine todos los servidores MCP remotos que no haya evaluado de la configuración de OpenCode del equipo (opencode mcp list muestra los que quedan).
  • Considere cualquier servidor que no pueda eliminar como una exposición aceptada: su página de inicio de sesión es donde llegaría el payload.
  • Los servidores MCP locales que ejecutan comandos instalados por usted quedan fuera de esta ruta, que necesita el intercambio OAuth de un servidor remoto.

¿Cuál es la causa raíz?

El intercambio de descubrimiento OAuth permitía al servidor MCP remoto elegir la URL de inicio de sesión, y OpenCode en Windows entregaba esa URL no confiable a una función de apertura de navegador que la interpolaba en un comando PowerShell sin escaparla.

La cadena en OpenCode 1.18.32: el documento de descubrimiento del servidor indica un authorization_endpoint, una cadena libre elegida por el servidor que pasa por el SDK MCP a oauth-provider.ts, después a mcp/index.ts, luego a browser.ts y finalmente a open(). OpenCode añadió la llamada que alcanza open() con la URL proporcionada por el servidor en el commit 509e43d6 del 7 de diciembre de 2025, fijando open en 10.1.2.

En macOS y Linux, open ejecuta open o xdg-open mediante spawn con un vector de argumentos, sin shell. En Windows, open 10.1.2 construye un comando PowerShell y el escape es asimétrico, como muestra su código:

// open@10.1.2, the Windows path (lines 242 to 256)
242:  encodedArguments.push(`"\`${app}\`""`);        // app gets escaped
247:  encodedArguments.push(`"${options.target}"`);    // target does not
256:  options.target = Buffer.from(
         encodedArguments.join(' '), 'utf16le').toString('base64');

La línea 242 escapa el nombre de la aplicación. La línea 247, el destino, justo donde llega la URL remota, no se escapa en absoluto. Los argumentos unidos se codifican en base64 y se entregan a powershell -EncodedCommand.

PowerShell expande subexpresiones $(...) dentro de cadenas entre comillas dobles. Ese es el error: una cadena remota, elegida por quien controla la respuesta del servidor MCP, pasa a formar parte de un comando PowerShell que el equipo del desarrollador ejecuta al iniciar sesión.

¿Cómo se explota?

No se han comunicado ataques y la prueba de concepto es pública en la divulgación de Pillar Security. Su payload es una dirección HTTPS perfectamente normal:

https://evil.test/$([IO.File]::WriteAllText('C:\Users\Public\pwned.txt','RCE'))

El ataque, paso a paso:

  1. El atacante controla un servidor MCP remoto configurado por el desarrollador o uno en el que puede influir al iniciar sesión: una toma de control, una entrada de registro secuestrada, un dominio de typosquatting o un dominio caducado que cambió de propietario.
  2. El desarrollador inicia la autenticación del servidor ejecutando opencode mcp auth. No necesita más interacción ni consentimiento: el intercambio es automático por diseño.
  3. El documento de descubrimiento del servidor devuelve la URL manipulada como su authorization_endpoint.
  4. OpenCode pasa la URL a open 10.1.2, que la interpola sin escape en el comando PowerShell y lo ejecuta.
  5. PowerShell evalúa la subexpresión $(...) antes de resolver el comando, por lo que el payload se ejecuta aunque después falle el lanzamiento del navegador. OpenCode descarta ese fallo.

El payload se ejecuta con los privilegios del desarrollador, en el equipo que contiene sus credenciales, tokens, árboles de código fuente y acceso a CI.

¿Cómo se desarrolla el ataque?

El ataque consiste en una única URL controlada por el servidor que se convierte en un comando PowerShell al iniciar sesión.

flowchart LR A["El desarrollador inicia sesión en
un servidor MCP remoto"] --> B["El documento de descubrimiento
devuelve una URL manipulada"] B --> C["OpenCode entrega la URL a
open@10.1.2 en Windows o WSL"] C --> D["open construye un comando PowerShell;
la URL de destino no se escapa"] D --> E["PowerShell evalúa la subexpresión
$(...) antes del lanzamiento"] E --> F["El payload se ejecuta como el desarrollador;
se descarta el fallo del lanzamiento"] style D fill:#f8d7da

La brecha está en D: nada escapaba la URL proporcionada por el servidor antes de introducirla en la línea de comandos.

¿Qué puede hacer un atacante?

Ejecutar código arbitrario como el desarrollador en un equipo Windows o WSL, lo que en la práctica significa acceder a todo lo que este alcance: árboles de código fuente, credenciales y tokens en disco, CLI de git y nube, acceso a CI y cualquier servidor MCP con el que pueda comunicarse el agente. Pillar califica el fallo como crítico, con CVSS v3.1 9.8 propuesto (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H), CWE-78 y CWE-88 secundario.

Las condiciones que necesita el ataque:

  • opencode-ai 1.0.137 a 1.18.32 o @opencode/cli 2.0.0 a 2.0.17 en Windows o WSL. macOS y Linux nunca pasan la URL por un shell.
  • Un servidor MCP remoto cuya respuesta de descubrimiento OAuth controle el atacante al iniciar sesión. No necesitaba ser malicioso cuando se configuró.
  • Que el desarrollador inicie la autenticación del servidor. Nada más: ni una pregunta ni consentimiento adicional.
  • La validación de esquema no ayuda: el payload es una URL https:// normal. Supera la lista de bloqueo javascript:/data:/vbscript: del SDK MCP TypeScript y las dos nuevas comprobaciones de esquema de OpenCode. También superaría la lista más estricta de permitidos http/https que el SDK consideró pero nunca publicó.

¿Por qué funciona la corrección?

OpenCode 1.18.33, integrado como commit 29f07e0c mediante la pull request #51414, cierra el fallo en tres capas, y el orden importa:

--- a/packages/core/src/open.ts (new file)
+import open from "open"
+
+export function openUrl(input: string) {
+  const url = URL.canParse(input) ? new URL(input) : undefined
+  if (!url || (url.protocol !== "http:" && url.protocol !== "https:"))
+    return Promise.reject(new Error(`Only http and https links can be opened in the browser: ${input}`))
+  return open(url.href)
+}

--- a/packages/opencode/src/mcp/oauth-provider.ts
   async redirectToAuthorization(authorizationUrl: URL): Promise<void> {
+    if (authorizationUrl.protocol !== "http:" && authorizationUrl.protocol !== "https:")
+      throw new Error(
+        `MCP server "${this.serverUrl}" returned a ${authorizationUrl.protocol} authorization URL; only http and https are supported`,
+      )
     await this.callbacks.onRedirect(authorizationUrl)
   }

--- a/package.json
-    "open": "10.1.2"
+    "open": "11.0.4"

La capa que realmente detiene el payload publicado es actualizar la dependencia. open 11.0.0, publicado el 15 de noviembre de 2025 con el commit 274d704, encierra el destino entre comillas simples, dentro de las cuales PowerShell no expande nada. Esa corrección llevaba diez meses disponible mientras OpenCode seguía fijado en 10.1.2. OpenCode añadió la llamada vulnerable await open(authorizationUrl) tres semanas después de publicarse el open corregido.

Las dos comprobaciones de esquema son defensa en profundidad, y es importante delimitar su efecto: el payload anterior es https://, de modo que ambas lo aceptan. Sin actualizar open, la corrección habría parecido completa y el agujero habría seguido abierto.

La corrección es completa para esta ruta: todos los puntos de lanzamiento de navegador pasan ahora por openUrl y el propio límite OAuth rechaza endpoints que no sean http(s). No hay aviso ni CVE. La postura de Anomaly, expresada al preguntársele, es que un servidor MCP malicioso queda fuera de su modelo de amenazas, por lo que el cambio se publicó descrito solo como una refactorización que comparte un abridor de navegador entre los paquetes opencode y tui. El diff es público, pero los escáneres que cotejan versiones con avisos publicados no tienen registro de este fallo.

¿Cómo compruebo si he sufrido una intrusión?

Pillar Security no comunicó señales de uso del fallo en ataques ni publicó indicadores. En equipos Windows y WSL que ejecutaron versiones afectadas con servidores MCP remotos configurados:

  • Ejecute opencode mcp list y revise la procedencia de cada servidor remoto: quién lo publica, dónde está registrado y si su dominio o entrada de registro podría haber cambiado de propietario desde que se configuró.
  • Considere cualquier creación inexplicada de procesos o archivos en torno a un inicio de sesión MCP, en un equipo con 1.0.137 a 1.18.32, motivo para la respuesta habitual a un compromiso del equipo de desarrollo: rote todas las credenciales, tokens y claves accesibles desde ese equipo y reconstruya el entorno desde un estado conocido como válido.
  • Tenga en cuenta el incidente independiente: una intrusión en la Console alojada de OpenCode, divulgada en fechas similares, podría haber expuesto claves de API de OpenAI, Anthropic y Google almacenadas por algunos usuarios. Es un suceso distinto de este fallo en el cliente.

Cronología

  • 2020-10-22: la incidencia #202 de open informa de una URL con $ que pierde caracteres en WSL 2, registrada como enlace roto cinco años antes de comprenderse como expansión de cadenas PowerShell.
  • 2021-09-17: el README de open añade su advertencia permanente de que el paquete no ofrece garantías de seguridad y sanear entradas no confiables es responsabilidad de quien lo llama.
  • 2023-07-24: las incidencias #318 y #319 de open tratan el escape de argumentos PowerShell.
  • 2023-10-18: la incidencia #323 de open informa de inyección de comandos del sistema operativo en Windows al abrir URL, con una prueba de concepto de una línea; se etiqueta como mejora y después se cierra como no planificada.
  • 2025-07-09: se publica CVE-2025-6514, el mismo defecto en el proxy mcp-remote, calificado con 9.6, con el análisis de JFrog que identifica open() como destino vulnerable.
  • 2025-08-28 y 2025-09-17: CVE-2025-58062 en openmcp-client y CVE-2025-10619 en sequa-mcp corresponden al mismo destino vulnerable.
  • 2025-11-15: open 11.0.0 publica el commit 274d704, que corrige el escape de argumentos PowerShell; las notas de versión lo enumeran entre las correcciones.
  • 2025-12-07: el commit 509e43d6 de OpenCode añade await open(authorizationUrl) a la ruta OAuth MCP, fijando open 10.1.2, tres semanas después de publicarse el open corregido.
  • 2026-08-29: Pillar Security comunica el fallo de forma privada mediante un GitHub Security Advisory con todo el material de reproducción.
  • 2026-09-25: la pull request #51414 se integra como commit 29f07e0c, descrito como refactorización; Anomaly confirma que el informe llegó al equipo y responde que los servidores MCP maliciosos quedan fuera de su modelo de amenazas.
  • 2026-09-28: OpenCode 1.18.33 se publica en npm con la corrección.
  • 2026-10-19: Pillar Security publica la divulgación tras pedir a Anomaly que reconsidere su postura y solicite un CVE.
  • 2026-10-26: este artículo.

Preguntas frecuentes

¿Por qué mi escáner no señalará esta vulnerabilidad?

No hay CVE ni aviso del proveedor porque Anomaly no solicitó ninguno después de corregir el fallo; las bases de vulnerabilidades no tienen con qué cotejar. El intervalo afectado solo se conoce por la corrección publicada como refactorización y por la divulgación de Pillar. Encontrar instalaciones afectadas exige comprobar versiones de paquetes npm con npm ls -g opencode-ai @opencode/cli y revisar los servidores MCP configurados con opencode mcp list, en lugar de depender de un escáner basado en avisos.

¿La validación del esquema de URL detiene este ataque?

No. El payload publicado es una URL https:// ordinaria. Supera la lista de bloqueo de javascript:, data: y vbscript: del SDK MCP TypeScript y las dos comprobaciones de esquema que OpenCode añadió en 1.18.33. También superaría la lista más estricta de permitidos http/https que el SDK consideró pero nunca publicó. Lo que cerró el agujero fue actualizar open a 11.0.0 o posterior (OpenCode subió a 11.0.4), que encierra el destino entre comillas simples para impedir que PowerShell lo expanda.

¿Están afectadas las instalaciones macOS y Linux?

No. En esas plataformas, open inicia el navegador mediante spawn con un vector de argumentos, de modo que no se construye un comando de shell ni se interpola ninguna cadena. Solo las compilaciones Windows y WSL siguen la ruta PowerShell.

¿Es lo mismo que la intrusión en OpenCode Console de las noticias?

No. La intrusión en Console fue un incidente independiente divulgado en fechas similares, en el que podrían haberse expuesto claves de API almacenadas de OpenAI, Anthropic y Google. Este fallo ejecuta código en el equipo del desarrollador mediante un inicio de sesión MCP y no necesita comprometer los sistemas de OpenCode.

¿Qué clientes MCP lo gestionan correctamente?

La revisión de Pillar identificó varias estrategias:

  • gemini-cli utiliza un abridor execFile condicionado por esquema, sin shell.
  • Claude Code protege el abridor para que la ruta OAuth no pueda alcanzarlo con un valor controlado por el servidor.
  • github-mcp-server obtiene los endpoints de autorización del operador en lugar de descubrirlos desde el otro extremo.
  • Docker mcp-gateway valida todos los endpoints OAuth mediante una lista de permitidos https y un abridor con argv.

Estas estrategias impiden que una cadena de un servidor remoto se convierta en sintaxis de shell.

¿Qué hago si no puedo actualizar ahora?

Elimine de la configuración de OpenCode en equipos Windows y WSL todos los servidores MCP remotos que no haya evaluado por completo, y vuelva a comprobar con opencode mcp list. Un servidor MCP local que ejecuta código instalado por usted queda fuera de la ruta del fallo, que necesita el intercambio OAuth de un servidor remoto.

Busque el intervalo de OpenCode sin parchear

Revise sus repositorios con Ostorlab Source Code Security Testing. En equipos de desarrollo y dentro de imágenes CI, ejecute npm ls -g opencode-ai @opencode/cli y compruebe si hay opencode-ai 1.0.137–1.18.32 o @opencode/cli 2.0.0–2.0.17. Estas comprobaciones identifican los intervalos afectados sin esperar una alerta basada en avisos.

Referencias

  • Pillar Security, «Abrir y cerrar: ejecución remota de código en opencode mediante OAuth MCP», 19 de octubre de 2026, con la causa raíz, el código citado de open 10.1.2, la prueba de concepto, la matriz de versiones afectadas y la cronología de divulgación: https://www.pillar.security/blog/open-and-shut-remote-code-execution-in-opencode-via-mcp-oauth (consultado el 26 de octubre de 2026)
  • Repositorio de OpenCode, anomalyco/opencode: https://github.com/anomalyco/opencode (consultado el 26 de octubre de 2026)
  • Commit vulnerable 509e43d6, que añade await open(authorizationUrl) el 7 de diciembre de 2025: https://github.com/anomalyco/opencode/commit/509e43d6 (referenciado mediante Pillar Security, 26 de octubre de 2026)
  • Corrección, pull request #51414, integrada como commit 29f07e0c el 25 de septiembre de 2026: https://github.com/anomalyco/opencode/pull/51414 y https://github.com/anomalyco/opencode/commit/29f07e0c (consultado el 26 de octubre de 2026)
  • OpenCode 1.18.33 en npm, publicado el 28 de septiembre de 2026, y las marcas de tiempo que confirman de 1.0.137 (9 de diciembre de 2025) a 1.18.32 (21 de septiembre de 2026) como rama afectada: https://www.npmjs.com/package/opencode-ai/v/1.18.33 y https://registry.npmjs.org/opencode-ai (consultado el 26 de octubre de 2026)
  • Corrección de v2, PR #51412, y manifiestos de etiquetas que confirman el cambio de dependencia de open 10.1.2 en v2.0.17 a 11.0.4 en v2.0.18: https://github.com/anomalyco/opencode/pull/51412, https://github.com/anomalyco/opencode/blob/v2.0.17/packages/cli/package.json y https://github.com/anomalyco/opencode/blob/v2.0.18/packages/util/package.json; marcas de tiempo de publicación npm: https://registry.npmjs.org/@opencode/cli (consultado el 28 de octubre de 2026)
  • Paquete open en 10.1.2, ruta Windows de la versión fijada: https://github.com/sindresorhus/open/tree/v10.1.2 (consultado el 26 de octubre de 2026)
  • Incidencia #202 de open, una URL con $ en WSL 2, 22 de octubre de 2020; incidencia #323, inyección de comandos del sistema operativo en Windows, 18 de octubre de 2023; y commit de corrección 274d704 en open 11.0.0, 15 de noviembre de 2025: https://github.com/sindresorhus/open/issues/202, https://github.com/sindresorhus/open/issues/323 y https://github.com/sindresorhus/open/commit/274d704 (consultado el 26 de octubre de 2026)
  • CVE-2025-6514, el mismo destino vulnerable en mcp-remote, CVSS v3.1 9.6, con el análisis de JFrog: https://nvd.nist.gov/vuln/detail/CVE-2025-6514 y https://jfrog.com/blog/2025-6514-critical-mcp-remote-rce-vulnerability/ (referenciado mediante Pillar Security, 26 de octubre de 2026)
  • CVE-2025-58062 en openmcp-client y CVE-2025-10619 en sequa-mcp, el mismo destino vulnerable: https://nvd.nist.gov/vuln/detail/CVE-2025-58062 y https://nvd.nist.gov/vuln/detail/CVE-2025-10619 (referenciado mediante Pillar Security, 26 de octubre de 2026)
  • The Hacker News sobre el fallo de OpenCode, 22 de octubre de 2026: https://thehackernews.com/2026/10/opencode-flaw-lets-malicious-mcp.html (consultado el 26 de octubre de 2026)
  • The Hacker News sobre la intrusión independiente en OpenCode Console: https://thehackernews.com/2026/10/opencode-console-breach-may-have.html (referenciado mediante el artículo de OpenCode, 26 de octubre de 2026)
  • Descargas semanales npm de opencode-ai, 2.180.172 en la semana hasta el 22 de octubre de 2026, y de @opencode/cli, 321.091: https://api.npmjs.org/downloads/point/2026-10-16:2026-10-22/opencode-ai y https://api.npmjs.org/downloads/point/last-week/@opencode/cli (consultado el 26 de octubre de 2026)
  • Descargas semanales npm del paquete open, 102.012.551 en la semana hasta el 22 de octubre de 2026: https://api.npmjs.org/downloads/point/last-week/open (consultado el 26 de octubre de 2026)
  • Recuento de estrellas GitHub de anomalyco/opencode, 221.765 a fecha del 26 de octubre de 2026: https://api.github.com/repos/anomalyco/opencode (consultado el 26 de octubre de 2026)