Neutron, notre moteur d’IA, a obtenu un score de 97,1 % sur le benchmark CyberGym de l’UC Berkeley. En savoir plus

Analyse approfondie

Analyse approfondie

OpenCode : RCE lors de la connexion OAuth MCP sur Windows, corrigée dans 1.18.33

Dans OpenCode 1.0.137 à 1.18.32 sur Windows et WSL, l’URL de connexion OAuth d’un serveur MCP malveillant atteint PowerShell et exécute du code sous l’identité du développeur ; corrigé dans 1.18.33, sans CVE.

En bref

  • Lors d’une connexion OAuth MCP, le serveur auprès duquel l’authentification est effectuée choisit l’adresse web vers laquelle le navigateur du développeur est envoyé. Dans OpenCode sur Windows et WSL, les versions 1.0.137 à 1.18.32 transmettaient cette URL contrôlée par le serveur au package open, qui construisait autour d’elle une commande PowerShell sans l’échapper. Une adresse contenant une sous-expression PowerShell s’exécutait donc sous l’identité du développeur.
  • Pillar Security, qui a découvert la faille et l’a signalée en privé le 29 août 2026, la classe comme critique avec un score proposé CVSS v3.1 de 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H), CWE-78. Il s’agit de l’évaluation proposée par Pillar : l’attaque documentée nécessite tout de même que le développeur exécute opencode mcp auth, après quoi la négociation ne demande aucune confirmation ni aucun consentement supplémentaire. Il n’y a ni CVE ni bulletin de l’éditeur : Anomaly, le développeur d’OpenCode, considère qu’un serveur MCP distant malveillant sort de son modèle de menace. Les scanners qui comparent les versions aux bulletins publiés n’ont donc aucune fiche pour cette faille.
  • macOS et Linux ne sont pas affectés, car OpenCode y ouvre le navigateur sans faire passer l’URL par un shell. Aucune attaque utilisant cette faille n’a été signalée, et Pillar n’a publié aucun indicateur de compromission.
  • Mettez à jour vers OpenCode 1.18.33 ou ultérieur, publié le 28 septembre 2026. Si vous ne pouvez pas encore le faire, retirez de la configuration OpenCode sur les machines Windows et WSL tout serveur MCP distant que vous n’avez pas entièrement évalué.

Suis-je concerné ?

Vous êtes concerné si vous utilisez opencode-ai 1.0.137–1.18.32 ou @opencode/cli 2.0.0–2.0.17 sur Windows ou WSL avec un serveur MCP distant dont vous ne contrôlez pas les réponses, et si vous lancez la connexion à ce serveur. Toutes ces conditions doivent être réunies :

  • Vous utilisez OpenCode sur Windows ou Windows Subsystem for Linux (WSL). Les installations macOS et Linux ne sont pas affectées : le lanceur de navigateur de ces plateformes ne fait jamais passer l’URL par un shell.
  • La version est opencode-ai 1.0.137 à 1.18.32 incluse, ou @opencode/cli 2.0.0 à 2.0.17 incluse.
  • Au moins un serveur MCP distant configuré renvoie des réponses que vous ne contrôlez pas entièrement. Il n’avait pas besoin d’être malveillant lors de sa configuration : le payload arrive dans une réponse HTTP au moment de la connexion. Un serveur compromis ultérieurement, une entrée de registre détournée, un typosquattage ou un domaine expiré ayant changé de propriétaire peuvent donc fournir la même adresse.
  • Le développeur lance la connexion à ce serveur en exécutant opencode mcp auth. Le simple fait de configurer le serveur ou d’ouvrir une session n’atteint pas l’étape d’ouverture du navigateur.
Package Versions affectées Version corrigée
opencode-ai sur npm, Windows et WSL 1.0.137 à 1.18.32 1.18.33 (28 septembre 2026)
opencode-ai sur npm, macOS et Linux non affecté sans objet
@opencode/cli sur npm, Windows et WSL 2.0.0 à 2.0.17 2.0.18 (25 septembre 2026)

opencode-ai a enregistré 2 180 172 téléchargements npm du 16 au 22 octobre 2026. Les téléchargements indiquent la portée du logiciel, pas le nombre d’installations affectées.

Vérifiez votre version et les serveurs configurés :

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

Le correctif se trouve dans l’arbre source partagé du projet depuis le 25 septembre 2026. Mettre l’un ou l’autre package à jour vers sa version actuelle supprime donc la faille ; la matrice de divulgation de Pillar Security couvre la branche opencode-ai.

Comment corriger le problème ?

Mettez opencode-ai à jour vers 1.18.33 ou ultérieur, ou @opencode/cli vers 2.0.18 ou ultérieur :

npm i -g opencode-ai@latest

Pour la branche du package @opencode/cli :

npm i -g @opencode/cli@latest

Si vous ne pouvez pas encore mettre à jour une machine Windows ou WSL :

  • Retirez de la configuration OpenCode de cette machine tout serveur MCP distant que vous n’avez pas évalué (opencode mcp list indique ceux qui restent).
  • Considérez un serveur que vous ne pouvez pas supprimer comme une exposition acceptée : sa page de connexion est l’endroit où le payload arriverait.
  • Les serveurs MCP locaux qui exécutent des commandes que vous installez vous-même ne suivent pas ce chemin, lequel nécessite la négociation OAuth d’un serveur distant.

Quelle est la cause racine ?

La négociation de découverte OAuth laissait le serveur MCP distant choisir l’URL de connexion. OpenCode sur Windows transmettait ensuite cette URL non fiable à une fonction d’ouverture de navigateur qui l’interpolait dans une commande PowerShell sans l’échapper.

La chaîne dans OpenCode 1.18.32 : le document de découverte du serveur indique un authorization_endpoint, une chaîne libre choisie par le serveur, qui passe par le SDK MCP vers oauth-provider.ts, puis mcp/index.ts, puis browser.ts, et enfin open(). OpenCode a ajouté l’appel atteignant open() avec l’URL fournie par le serveur dans le commit 509e43d6 du 7 décembre 2025, en figeant open à la version 10.1.2.

Sur macOS et Linux, open exécute open ou xdg-open via spawn avec un vecteur d’arguments, sans shell. Sur Windows, open 10.1.2 construit une commande PowerShell, et l’échappement est asymétrique, comme le montre son propre code :

// 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 ligne 242 échappe le nom de l’application. La ligne 247, la cible, précisément là où arrive l’URL distante, n’est pas échappée du tout. Les arguments assemblés sont encodés en base64 et transmis à powershell -EncodedCommand.

PowerShell développe les sous-expressions $(...) à l’intérieur des chaînes entre guillemets doubles. C’est le bug : une chaîne distante, choisie par la personne qui contrôle la réponse du serveur MCP, devient une partie d’une commande PowerShell exécutée par la machine du développeur au moment de la connexion.

Comment la faille est-elle exploitée ?

Aucune attaque n’a été signalée, et la preuve de concept figure publiquement dans la divulgation de Pillar Security. Son payload est une adresse HTTPS parfaitement ordinaire :

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

L’attaque, étape par étape :

  1. L’attaquant contrôle un serveur MCP distant configuré par le développeur, ou un serveur dont il peut influencer les réponses au moment de la connexion : prise de contrôle, entrée de registre détournée, typosquattage ou domaine expiré ayant changé de propriétaire.
  2. Le développeur lance la connexion à ce serveur en exécutant opencode mcp auth. Aucune interaction ni aucun consentement supplémentaire n’est nécessaire ; la négociation est automatique par conception.
  3. Le document de découverte du serveur renvoie l’URL spécialement conçue comme authorization_endpoint.
  4. OpenCode transmet l’URL à open 10.1.2, qui l’interpole dans la commande PowerShell sans l’échapper puis l’exécute.
  5. PowerShell évalue la sous-expression $(...) avant de résoudre la commande. Le payload s’exécute donc même si l’ouverture du navigateur échoue ensuite. OpenCode ignore cet échec.

Le payload s’exécute avec les privilèges du développeur, sur la machine qui détient ses identifiants, ses jetons, ses arborescences de code source et ses accès CI.

Quel est le déroulement de l’attaque ?

L’attaque repose sur une seule URL contrôlée par le serveur, qui devient une commande PowerShell lors de la connexion.

flowchart LR A["Le développeur lance la connexion
à un serveur MCP distant"] --> B["Le document de découverte du serveur
renvoie une URL spécialement conçue"] B --> C["OpenCode transmet l’URL à
open@10.1.2 sur Windows ou WSL"] C --> D["open construit une commande PowerShell ;
l’URL cible n’est pas échappée"] D --> E["PowerShell évalue la sous-expression
$(...) avant le lancement"] E --> F["Le payload s’exécute comme le développeur ;
l’échec du lancement est ignoré"] style D fill:#f8d7da

La lacune se situe en D : rien n’échappait l’URL fournie par le serveur avant son entrée dans la ligne de commande.

Que peut faire un attaquant ?

Exécuter du code arbitraire sous l’identité du développeur sur une machine Windows ou WSL, ce qui donne en pratique accès à tout ce que le développeur peut atteindre : arborescences de code source, identifiants et jetons sur disque, CLI git et cloud, accès CI et tout serveur MCP avec lequel l’agent peut communiquer. Pillar classe la faille comme critique, avec un score proposé CVSS v3.1 de 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H), CWE-78, et CWE-88 comme classification secondaire.

Conditions nécessaires à l’attaque :

  • opencode-ai 1.0.137 à 1.18.32 ou @opencode/cli 2.0.0 à 2.0.17 sur Windows ou WSL. macOS et Linux ne transmettent jamais l’URL à un shell.
  • Un serveur MCP distant dont l’attaquant contrôle la réponse de découverte OAuth au moment de la connexion. Il n’avait pas besoin d’être malveillant lors de sa configuration.
  • Le lancement par le développeur de la connexion à ce serveur. Rien de plus : aucune confirmation ni aucun consentement supplémentaire.
  • La validation du schéma ne suffit pas : le payload est une simple URL https://. Il passe la liste de refus javascript:/data:/vbscript: du SDK MCP TypeScript et les deux nouvelles vérifications de schéma d’OpenCode. Il passerait également la liste d’autorisation http/https plus stricte envisagée par le SDK, mais jamais publiée.

Pourquoi le correctif fonctionne-t-il ?

OpenCode 1.18.33, intégré comme commit 29f07e0c via la pull request #51414, ferme la faille en trois couches, et l’ordre compte :

--- 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 couche qui bloque réellement le payload publié est la mise à jour de la dépendance. open 11.0.0, publié le 15 novembre 2025 avec le commit 274d704, entoure la cible de guillemets simples, et PowerShell ne développe rien à l’intérieur de tels guillemets. Ce correctif existait depuis dix mois alors qu’OpenCode restait figé sur 10.1.2. OpenCode a ajouté l’appel vulnérable await open(authorizationUrl) trois semaines après la publication de la version corrigée d’open.

Les deux vérifications de schéma sont une défense en profondeur, et leur portée doit être décrite précisément : le payload ci-dessus utilise https://, il passe donc les deux nouvelles vérifications. Sans la mise à jour d’open, le correctif aurait semblé complet alors que la faille serait restée ouverte.

Le correctif est complet pour ce chemin : tous les sites d’appel d’ouverture de navigateur passent désormais par openUrl, et la frontière OAuth elle-même rejette les endpoints non-http(s). Il n’y a ni bulletin ni CVE. La position d’Anomaly, communiquée en réponse aux questions, est qu’un serveur MCP malveillant sort de son modèle de menace. Le changement a donc été livré comme une simple refactorisation partageant une fonction d’ouverture de navigateur entre les packages opencode et tui. Le diff est public, mais les scanners comparant les versions aux bulletins publiés n’ont aucune fiche pour cette faille.

Comment vérifier si j’ai été compromis ?

Pillar Security n’a signalé aucun signe d’utilisation de cette faille dans des attaques et n’a publié aucun indicateur. Sur les machines Windows et WSL qui utilisaient une version affectée avec des serveurs MCP distants configurés :

  • Exécutez opencode mcp list et examinez la provenance de chaque serveur distant : qui le publie, où il est enregistré, et si son domaine ou son entrée de registre a pu changer de propriétaire depuis sa configuration.
  • Considérez toute création de processus ou de fichier inexpliquée autour d’une connexion MCP, sur une machine exécutant 1.0.137 à 1.18.32, comme un motif d’appliquer la réponse habituelle à la compromission d’un poste de développement : renouvelez tous les identifiants, jetons et clés accessibles depuis cette machine, puis reconstruisez l’environnement à partir d’un état réputé sain.
  • Notez l’incident distinct : une compromission de la Console hébergée d’OpenCode, divulguée à peu près à la même période, a pu exposer les clés d’API OpenAI, Anthropic et Google stockées par certains utilisateurs. Cet événement est différent de la faille dans le client décrite ici.

Chronologie

  • 2020-10-22 : l’issue open #202 signale une URL contenant $ qui perd des caractères sur WSL 2. Elle est enregistrée comme lien cassé, cinq ans avant que le problème soit compris comme un développement de chaîne PowerShell.
  • 2021-09-17 : le README d’open ajoute son avertissement permanent selon lequel le package ne fournit aucune garantie de sécurité et l’assainissement des entrées non fiables incombe à l’appelant.
  • 2023-07-24 : les issues open #318 et #319 traitent de l’échappement des arguments PowerShell.
  • 2023-10-18 : l’issue open #323 signale une injection de commandes système sous Windows lors de l’ouverture d’URL, avec une preuve de concept en une ligne ; elle est classée comme amélioration puis fermée comme non prévue.
  • 2025-07-09 : CVE-2025-6514, le même défaut dans le proxy mcp-remote, noté 9.6, est publiée avec l’analyse de JFrog qui identifie open() comme point d’exécution.
  • 2025-08-28 et 2025-09-17 : CVE-2025-58062 dans openmcp-client et CVE-2025-10619 dans sequa-mcp concernent le même point d’exécution.
  • 2025-11-15 : open 11.0.0 est publié avec le commit 274d704, qui corrige l’échappement des arguments PowerShell ; les notes de version le rangent sous Fixes.
  • 2025-12-07 : le commit OpenCode 509e43d6 ajoute await open(authorizationUrl) au chemin OAuth MCP, en figeant open à 10.1.2, trois semaines après la publication de la version corrigée d’open.
  • 2026-08-29 : Pillar Security signale la faille en privé via un GitHub Security Advisory avec tous les éléments de reproduction.
  • 2026-09-25 : la pull request #51414 est intégrée comme commit 29f07e0c, décrite comme une refactorisation ; Anomaly confirme que le signalement a atteint l’équipe et répond que les serveurs MCP malveillants sortent de son modèle de menace.
  • 2026-09-28 : OpenCode 1.18.33 est publié sur npm avec le correctif.
  • 2026-10-19 : Pillar Security publie la divulgation après avoir demandé à Anomaly de reconsidérer sa position et de demander une CVE.
  • 2026-10-26 : publication de cet article.

FAQ

Pourquoi mon scanner ne signalera-t-il pas cette vulnérabilité ?

Il n’y a ni CVE ni bulletin de l’éditeur, car Anomaly n’en a demandé aucun après avoir corrigé la faille. Les bases de vulnérabilités n’ont donc aucune entrée à laquelle comparer les versions. La plage affectée n’est connue que grâce au correctif livré comme refactorisation et à la divulgation de Pillar. Trouver les installations affectées nécessite de vérifier les versions des packages npm avec npm ls -g opencode-ai @opencode/cli et d’examiner les serveurs MCP configurés avec opencode mcp list, plutôt que de compter sur un scanner fondé sur les bulletins.

La validation du schéma d’URL bloque-t-elle cette attaque ?

Non. Le payload publié est une URL https:// ordinaire. Il passe la liste de refus javascript:, data: et vbscript: du SDK MCP TypeScript, ainsi que les deux vérifications de schéma ajoutées par OpenCode dans 1.18.33. Il passerait aussi la liste d’autorisation http/https plus stricte envisagée mais jamais publiée par le SDK. La correction effective est la mise à jour d’open vers 11.0.0 ou ultérieur (OpenCode est passé à 11.0.4), qui place la cible entre guillemets simples pour empêcher PowerShell de la développer.

Les installations macOS et Linux sont-elles affectées ?

Non. Sur ces plateformes, open lance le navigateur via spawn avec un vecteur d’arguments : aucune commande shell n’est construite et aucune chaîne n’est interpolée. Seuls les builds Windows et WSL empruntent le chemin PowerShell.

Est-ce le même incident que la compromission d’OpenCode Console dans l’actualité ?

Non. La compromission de Console est un incident distinct divulgué à peu près à la même période, au cours duquel des clés d’API OpenAI, Anthropic et Google stockées ont pu être exposées. Cette faille exécute du code sur la machine du développeur via une connexion MCP et ne nécessite aucune compromission des systèmes d’OpenCode.

Quels clients MCP gèrent correctement ce cas ?

L’examen de Pillar a identifié plusieurs approches :

  • gemini-cli utilise une fonction d’ouverture execFile avec filtrage du schéma, sans shell.
  • Claude Code protège la fonction d’ouverture pour que le chemin OAuth ne puisse pas l’atteindre avec une valeur contrôlée par le serveur.
  • github-mcp-server reçoit les endpoints d’autorisation de l’opérateur au lieu de les découvrir auprès du pair.
  • Docker mcp-gateway valide chaque endpoint OAuth derrière une liste d’autorisation https avec une fonction d’ouverture utilisant argv.

Ces approches empêchent la chaîne d’un serveur distant de devenir de la syntaxe shell.

Que faire si je ne peux pas mettre à jour immédiatement ?

Retirez de la configuration OpenCode des machines Windows et WSL tous les serveurs MCP distants que vous n’avez pas entièrement évalués, puis vérifiez à nouveau avec opencode mcp list. Un serveur MCP local qui exécute du code installé par vous-même sort du chemin de cette faille, qui nécessite la négociation OAuth d’un serveur distant.

Recherchez les versions OpenCode non corrigées

Examinez vos dépôts avec Ostorlab Source Code Security Testing. Sur les postes des développeurs et dans les images CI, exécutez npm ls -g opencode-ai @opencode/cli et recherchez opencode-ai 1.0.137–1.18.32 ou @opencode/cli 2.0.0–2.0.17. Ces vérifications de version identifient les plages affectées sans attendre une alerte fondée sur un bulletin.

Références

  • Pillar Security, « Open and Shut: Remote Code Execution in opencode via MCP OAuth », 19 octobre 2026, avec la cause racine, le code cité d’open 10.1.2, la preuve de concept, la matrice des versions affectées et la chronologie de divulgation : https://www.pillar.security/blog/open-and-shut-remote-code-execution-in-opencode-via-mcp-oauth (consulté le 26 octobre 2026)
  • Dépôt OpenCode, anomalyco/opencode : https://github.com/anomalyco/opencode (consulté le 26 octobre 2026)
  • Commit vulnérable 509e43d6, ajoutant await open(authorizationUrl) le 7 décembre 2025 : https://github.com/anomalyco/opencode/commit/509e43d6 (référencé via Pillar Security, 26 octobre 2026)
  • Correctif, pull request #51414, intégré comme commit 29f07e0c le 25 septembre 2026 : https://github.com/anomalyco/opencode/pull/51414 et https://github.com/anomalyco/opencode/commit/29f07e0c (consultés le 26 octobre 2026)
  • OpenCode 1.18.33 sur npm, publié le 28 septembre 2026, et horodatages confirmant la plage affectée de 1.0.137 (9 décembre 2025) à 1.18.32 (21 septembre 2026) : https://www.npmjs.com/package/opencode-ai/v/1.18.33 et https://registry.npmjs.org/opencode-ai (consultés le 26 octobre 2026)
  • Correctif v2, PR #51412, et manifestes des tags de version confirmant le passage de la dépendance open 10.1.2 dans v2.0.17 à 11.0.4 dans v2.0.18 : https://github.com/anomalyco/opencode/pull/51412, https://github.com/anomalyco/opencode/blob/v2.0.17/packages/cli/package.json et https://github.com/anomalyco/opencode/blob/v2.0.18/packages/util/package.json; horodatages de publication npm : https://registry.npmjs.org/@opencode/cli (consultés le 28 octobre 2026)
  • Package open à la version 10.1.2, chemin Windows de la version figée : https://github.com/sindresorhus/open/tree/v10.1.2 (consulté le 26 octobre 2026)
  • Issue open #202, URL avec $ sur WSL 2, 22 octobre 2020 ; issue #323, injection de commandes système sur Windows, 18 octobre 2023 ; et commit de correction 274d704 dans open 11.0.0, 15 novembre 2025 : https://github.com/sindresorhus/open/issues/202, https://github.com/sindresorhus/open/issues/323 et https://github.com/sindresorhus/open/commit/274d704 (consultés le 26 octobre 2026)
  • CVE-2025-6514, même point d’exécution dans mcp-remote, CVSS v3.1 9.6, avec l’analyse de JFrog : https://nvd.nist.gov/vuln/detail/CVE-2025-6514 et https://jfrog.com/blog/2025-6514-critical-mcp-remote-rce-vulnerability/ (référencée via Pillar Security, 26 octobre 2026)
  • CVE-2025-58062 dans openmcp-client et CVE-2025-10619 dans sequa-mcp, même point d’exécution : https://nvd.nist.gov/vuln/detail/CVE-2025-58062 et https://nvd.nist.gov/vuln/detail/CVE-2025-10619 (référencées via Pillar Security, 26 octobre 2026)
  • The Hacker News sur la faille OpenCode, 22 octobre 2026 : https://thehackernews.com/2026/10/opencode-flaw-lets-malicious-mcp.html (consulté le 26 octobre 2026)
  • The Hacker News sur la compromission distincte d’OpenCode Console : https://thehackernews.com/2026/10/opencode-console-breach-may-have.html (référencé via l’article OpenCode, 26 octobre 2026)
  • Téléchargements npm hebdomadaires d’opencode-ai, 2 180 172 pour la semaine se terminant le 22 octobre 2026, et de @opencode/cli, 321 091 : https://api.npmjs.org/downloads/point/2026-10-16:2026-10-22/opencode-ai et https://api.npmjs.org/downloads/point/last-week/@opencode/cli (consultés le 26 octobre 2026)
  • Téléchargements npm hebdomadaires du package open, 102 012 551 pour la semaine se terminant le 22 octobre 2026 : https://api.npmjs.org/downloads/point/last-week/open (consultés le 26 octobre 2026)
  • Nombre d’étoiles GitHub pour anomalyco/opencode, 221 765 au 26 octobre 2026 : https://api.github.com/repos/anomalyco/opencode (consulté le 26 octobre 2026)