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

Contournement d'authentification Xen Orchestra exploité pour prendre le contrôle des hôtes (VSA-2026-062)

Un objet JSON vide dans le cookie authenticationToken contourne l'authentification de Xen Orchestra et donne un accès admin ; 6.9.2 corrige.

En bref

  • Un objet JSON vide dans le cookie authenticationToken fait traiter la requête comme une requête d'administrateur authentifié. La recherche de jeton reçoit l'objet, le traite comme une requête sans filtre et renvoie le premier jeton stocké.
  • Xen Orchestra avant 6.9.2 sur le canal stable et avant 6.10.1 sur le canal latest est concerné, y compris la Xen Orchestra Appliance. Les paquets xo-server sont 5.211.2 et 5.213.1.
  • Le fournisseur classe la faille Critique et indique qu'elle est activement exploitée. Aucun CVE n'est attribué, et la faille ne figure pas dans le catalogue Known Exploited Vulnerabilities de la CISA au 11 novembre 2026.
  • Mettez à jour vers 6.9.2 ou 6.10.1, ou xo-server 5.211.2 ou 5.213.1. Sans mise à jour, bloquez le cookie vide au proxy et retirez l'instance d'Internet.

Suis-je concerné ?

Toutes ces conditions doivent être réunies :

  • Vous utilisez Xen Orchestra avant 6.9.2 sur le canal stable ou avant 6.10.1 sur le canal latest. La Xen Orchestra Appliance est aussi concernée.
  • L'API REST est joignable par l'attaquant. Le chemin vulnérable est le middleware d'authentification REST, qui lit le cookie authenticationToken.
  • L'instance possède au moins un jeton d'authentification non expiré dans sa collection. Un jeton est créé lorsqu'un utilisateur se connecte et choisit de rester connecté, donc la plupart des déploiements actifs en ont un.

Le fournisseur indique que la faille est dans Xen Orchestra, pas dans XCP-ng. L'impact atteint les pools gérés parce que Xen Orchestra détient leurs identifiants d'administrateur. Une console compromise peut exécuter des commandes sur chaque hôte qu'elle gère.

Xen Orchestra est la console de gestion de XCP-ng, l'alternative open source à XenServer. Le dépôt du projet compte 998 étoiles sur GitHub, et l'image de conteneur communautaire ronivay/xen-orchestra totalise 2 777 836 téléchargements sur Docker Hub, un indice du nombre de déploiements qui exécutent la console.

Canal Versions concernées Versions corrigées
Stable Xen Orchestra avant 6.9.2, xo-server avant 5.211.2 Xen Orchestra 6.9.2, xo-server 5.211.2
Latest Xen Orchestra avant 6.10.1, xo-server avant 5.213.1 Xen Orchestra 6.10.1, xo-server 5.213.1

Vérifiez la version du paquet xo-server. Sur une installation depuis les sources, exécutez ceci à la racine du dépôt :

node -p "require('./packages/xo-server/package.json').version"
npm ls xo-server -g --depth=0

Sur la Xen Orchestra Appliance, ouvrez la page About dans l'interface web et lisez la version de Xen Orchestra. Le fournisseur publie aussi les versions xo-server corrigées dans l'avis. Si la version est 5.211.2 ou 5.213.1, l'instance possède le correctif ; les numéros précédents sont concernés.

Comment corriger ?

Mettez à jour Xen Orchestra vers 6.9.2 sur le canal stable ou 6.10.1 sur le canal latest, puis redémarrez le service. Les installations depuis les sources doivent passer au dernier master et reconstruire.

  1. Sur le canal stable, mettez à jour vers Xen Orchestra 6.9.2, qui embarque xo-server 5.211.2.
  2. Sur le canal latest, mettez à jour vers Xen Orchestra 6.10.1, qui embarque xo-server 5.213.1.
  3. Sur une installation depuis les sources, récupérez le dernier master, exécutez les étapes d'installation et de build habituelles, puis redémarrez xo-server.
  4. Confirmez la nouvelle version de xo-server avec la commande de « Suis-je concerné ? ».
  5. Si vous utilisez l'appliance, appliquez la mise à jour du fournisseur et vérifiez que la page About affiche 6.9.2 ou 6.10.1.

Si vous ne pouvez pas mettre à jour, retirez l'instance d'Internet et bloquez le jeton vide au proxy. Le fournisseur liste trois mesures :

  1. Placez Xen Orchestra sur un réseau de gestion dédié et ne l'exposez pas à Internet.
  2. Bloquez les adresses IP et le domaine Tor que le fournisseur associe à la campagne. La liste figure dans « Comment vérifier si j'ai été compromis ? ».
  3. Ajoutez une règle WAF ou de reverse proxy qui rejette authenticationToken=j:{} et authenticationToken=j:%7B%7D. Le fournisseur avertit que les règles regex peuvent être contournées par d'autres encodages, donc traitez-la comme une mesure provisoire.

Faites tourner tous les identifiants que la console peut atteindre si vous trouvez le moindre signe de compromission. Cela inclut le secret du pool, les mots de passe root des hôtes, les comptes utilisateurs, les secrets OTP, les identifiants des cibles de sauvegarde et les mots de passe du serveur de messagerie. Le fournisseur recommande une réinstallation complète après une compromission confirmée, car un nettoyage seul ne garantit pas la disparition d'une porte dérobée.

Quelle est la cause racine ?

L'API REST analyse les cookies avec le middleware cookie-parser, qui comprend le préfixe j: comme du JSON. Une valeur de cookie authenticationToken=j:%7B%7D est décodée en objet vide {}. Le middleware REST transmet ensuite cet objet au fournisseur d'authentification comme jeton :

  async #authenticateUser(req) {
    const { cookies, ip } = req
    const token = cookies.authenticationToken ?? cookies.token

    if (!token) {
      throw invalidCredentials()
    }

    const { user } = await this.#app.authenticateUser({ token }, { ip })

Le fournisseur vérifie seulement si la valeur est vraie. Un objet vide est vrai, donc la requête continue :

    this.registerAuthenticationProvider(async ({ token: tokenId }, { ip } = {}) => {
      if (!tokenId) {
        return
      }

      try {
        const token = await app.getAuthenticationToken(tokenId)

getAuthenticationToken attend une chaîne ou un objet avec un champ id. Il lit properties.id sans vérifier le type, donc l'objet vide produit undefined :

  async getAuthenticationToken(properties) {
    const id = typeof properties === 'string' ? properties : properties.id

    const token = await this._getAuthenticationToken(id, properties)

_getAuthenticationToken transmet ensuite l'objet d'origine à la collection de jetons lorsqu'il est présent :

  async _getAuthenticationToken(id, properties) {
    const token = await this._tokens.first(properties ?? id)

Le first({}) de la collection traite un objet vide comme une requête sans condition et renvoie le premier jeton qu'elle contient. Si ce jeton n'est pas expiré, le fournisseur authentifie la requête comme son propriétaire. L'attaquant n'a besoin d'aucun identifiant ; l'objet lui-même sélectionne l'enregistrement.

Comment la faille est-elle exploitée ?

  1. L'attaquant envoie une requête HTTP à l'API REST de Xen Orchestra avec le cookie authenticationToken=j:%7B%7D (ou authenticationToken=j:{}).
  2. cookie-parser décode la valeur j: en objet vide {}.
  3. Le middleware REST transmet { token: {} } au fournisseur d'authentification. Le contrôle de véracité du fournisseur accepte l'objet.
  4. getAuthenticationToken lit properties.id, qui vaut undefined, et transmet l'objet d'origine à la collection de jetons.
  5. Le first({}) de la collection renvoie le premier jeton. Le fournisseur vérifie son expiration et authentifie la requête comme son propriétaire.
  6. L'attaquant appelle /rest/v0/users/me/authentication_tokens avec la session obtenue et reçoit des identifiants de jetons de connexion réutilisables.
  7. L'attaquant utilise une session administrateur pour modifier la configuration, exécuter des commandes sur les pools gérés et atteindre les hôtes XCP-ng en root.

Le fournisseur indique que l'exploit peut mener à l'exécution de code arbitraire sur les pools gérés et à la prise de contrôle complète d'un nœud XCP-ng en root. Il ne publie pas la séquence de requêtes exacte au-delà du motif de cookie, et les indicateurs donnés dans cet avis sont ceux de la campagne, pas une méthode de détection complète.

Comment se déroule l'attaque ?

Un objet JSON vide remplace l'identifiant de jeton, la collection renvoie son premier enregistrement, et la requête devient une session administrateur qui atteint les hôtes gérés.

flowchart LR A["L'attaquant envoie authenticationToken=j:%7B%7D"] --> B["cookie-parser transforme j: en {}"] B --> C["Le middleware REST transmet { token: {} }"] C --> D["Le fournisseur accepte l'objet vrai
aucun contrôle de chaîne"] D --> E["La collection first({})
renvoie le premier jeton"] E --> F["Session comme propriétaire du jeton
souvent un administrateur"] F --> G["Commandes sur les pools gérés
et les hôtes XCP-ng"]

Que peut faire un attaquant ?

Un attaquant qui atteint l'API REST peut s'authentifier comme le propriétaire du premier jeton non expiré. En pratique, c'est un administrateur, car la session peut ensuite appeler les routes REST réservées aux administrateurs.

L'impact comprend :

  • La lecture et la modification de la configuration de Xen Orchestra, des utilisateurs et des jetons d'authentification.
  • L'exécution de commandes sur les pools gérés via l'accès aux hôtes de Xen Orchestra.
  • La prise de contrôle d'un nœud XCP-ng en root, comme le décrit le fournisseur.
  • La collecte de la configuration et des identifiants des proxys, des cibles de sauvegarde (NFS, S3, Azure, SMB), du compte root, du secret du pool, des comptes utilisateurs, des secrets OTP et des paramètres du serveur de messagerie.

Les conditions sont celles de « Suis-je concerné ? » : une version concernée de Xen Orchestra, l'API REST joignable par l'attaquant et au moins un jeton non expiré dans la collection. Le fournisseur indique que la faille est activement exploitée, donc une instance exposée à Internet doit être traitée comme exposée avant même d'y trouver un jeton.

Pourquoi le correctif fonctionne-t-il ?

Le correctif valide l'identifiant de jeton avant qu'il n'atteigne la collection et construit la requête uniquement à partir des champs validés. Il ajoute un contrôle de chaîne et modifie la recherche :

+const isNonEmptyString = value => typeof value === 'string' && value.length !== 0
+
 export default class {
@@
     this.registerAuthenticationProvider(async ({ token: tokenId }, { ip } = {}) => {
-      if (!tokenId) {
+      if (!isNonEmptyString(tokenId)) {
         return
       }
@@
-  async _getAuthenticationToken(id, properties) {
-    const token = await this._tokens.first(properties ?? id)
+  async _getAuthenticationToken(id, userId) {
+    if (!isNonEmptyString(id) || (userId !== undefined && !isNonEmptyString(userId))) {
+      return
+    }
+
+    // build the query from validated fields only, never forward caller-supplied objects
+    const token = await this._tokens.first(userId === undefined ? id : { id, user_id: userId })

getAuthenticationToken ne récupère plus que id et user_id de l'entrée et transmet ces valeurs à la recherche privée. Un cookie qui se décode en {} échoue au contrôle de chaîne avant toute requête à la base. Un jeton chaîne valide fonctionne toujours, et une recherche composée { id, user_id } est préservée. Les clés supplémentaires ajoutées par un attaquant à l'objet sont ignorées.

Le correctif est complet pour le chemin décrit. L'avis du fournisseur indique que l'API REST, la route de connexion et la méthode JSON-RPC session.signIn rejettent désormais les identifiants de jeton non-chaîne et vides. Il ne couvre pas le code tiers qui appelle le fournisseur de jetons avec son propre objet, donc gardez l'instance hors d'Internet.

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

Le fournisseur indique qu'il n'existe aucune entrée de journal pour un accès non authentifié réussi, donc la capture de paquets est la vérification la plus directe. Capturez le trafic sur l'hôte Xen Orchestra ou son reverse proxy et cherchez le motif de cookie, y compris la forme encodée :

tcpdump -i any -A -s 0 'tcp port 80 or tcp port 443' | grep -iE 'authenticationToken=j:(%7B%7D|\{\})'
grep -iE 'authenticationToken=j:(%7B%7D|\{\})' /var/log/nginx/access.log

La même requête apparaît dans les indicateurs du fournisseur sous authenticationToken=j:%7B%7D ou authenticationToken=j:{}. Une correspondance est une piste : les clients légitimes ne doivent pas envoyer d'objet vide comme jeton.

Vérifiez les hôtes XCP-ng pour les artefacts de la campagne :

xe vm-list params=name-label,platform | grep -B1 'hvm_serial: file'
zgrep -- '-serial file:' /var/log/xensource.log*
ls -la /etc/ld.so.preload /.ustar* /etc/cron.d/zz-ustar*

Les indicateurs du fournisseur incluent une machine virtuelle nommée pivot2, des VM configurées avec le paramètre hvm_serial: file, et les fichiers /etc/cron.d/zz-ustar2, /etc/cron.d/zz-ustar, /.ustar5 et /.ustar6. Il liste aussi les adresses IP 91.211.251.112, 193.148.56.72, 37.221.208.216, 45.66.35.11, 64.65.0.120, 64.65.62.160, 89.47.51.90 et 92.60.37.247, ainsi que le domaine Tor ustar3rqxgnskzgnwkgpofgtvxevm6cx3lxdbwt4mndtveqyaohid.onion.

Si vous trouvez l'un de ces éléments, faites tourner tous les identifiants que la console peut atteindre et reconstruisez l'instance. Le fournisseur indique qu'un nettoyage seul ne garantit pas la suppression de toutes les portes dérobées.

Chronologie

  • 2026-11-10 08:29 UTC : le commit de correction 50166fe3 est fusionné via la pull request #10748.
  • 2026-11-10 : Vates publie VSA-2026-062 et les versions corrigées Xen Orchestra 6.9.2 et 6.10.1.
  • 2026-11-10 : le fournisseur signale une exploitation active depuis l'adresse IP et le domaine Tor listés.

Chronologie du correctif, de la divulgation et du signalement de l'exploitation le 10 novembre 2026
Figure 1 : Vates a fusionné le correctif, publié l'avis et signalé une exploitation active le même jour. Source : avis Vates et pull request #10748, vérifiés le 11 novembre 2026

FAQ

Y a-t-il un CVE ?

Aucun CVE n'est attribué au 11 novembre 2026. Le fournisseur suit le problème sous VSA-2026-062, et l'avis fait foi. L'absence de CVE ne rend pas la faille moins urgente : le fournisseur indique qu'elle est activement exploitée.

Cela concerne-t-il directement les hôtes XCP-ng ?

La faille est dans Xen Orchestra, pas dans le logiciel des hôtes XCP-ng. Les hôtes sont à risque parce que Xen Orchestra les gère avec des identifiants privilégiés. Un attaquant qui prend le contrôle de la console peut utiliser cet accès pour exécuter des commandes sur les hôtes, ce qui explique la prise de contrôle complète décrite par le fournisseur.

Quelle version dois-je installer ?

Installez Xen Orchestra 6.9.2 sur le canal stable ou 6.10.1 sur le canal latest. Sur une installation depuis les sources, passez au dernier master et vérifiez que xo-server est 5.211.2 ou 5.213.1. La mise à jour de l'appliance embarque le même correctif.

Une règle qui rejette authenticationToken=j:{} et authenticationToken=j:%7B%7D bloque la requête de la campagne, mais le fournisseur avertit que d'autres encodages peuvent contourner une regex étroite. Utilisez la règle seulement jusqu'à la mise à jour, et gardez l'instance hors d'Internet.

La faille a-t-elle été exploitée comme zero-day ?

Le fournisseur indique que la faille est activement exploitée, mais ne dit pas quand l'activité a commencé ni si les attaques ont précédé le correctif. Il ne dit pas non plus si la vulnérabilité a servi de zero-day. Traitez la fenêtre d'exposition comme inconnue et vérifiez les hôtes pour les artefacts listés.

Que dois-je faire tourner après une compromission ?

Faites tourner tous les identifiants que l'appliance peut atteindre : le secret du pool, les mots de passe root des hôtes, les comptes utilisateurs Xen Orchestra, les secrets OTP, la configuration du proxy, les identifiants des cibles de sauvegarde NFS, S3, Azure et SMB, et le mot de passe du serveur de messagerie. Reconstruisez l'appliance depuis une image saine après la rotation.

Trouver les consoles Xen Orchestra exposées avec Ostorlab

La découverte de surface d'attaque d'Ostorlab inventorie les hôtes exposés à Internet de votre parc, afin de voir quelles consoles Xen Orchestra et quelles interfaces de gestion répondent depuis l'extérieur de votre réseau avant de les corriger. Utilisez l'inventaire pour trouver les consoles qui devraient être sur un réseau de gestion et pour prioriser celles qui restent exposées.

Références

  • Avis Vates VSA-2026-062 : https://docs.vates.tech/security-advisories/advisories/2026/vates-sa-2026-062/ (vérifié le 11 novembre 2026)
  • Pull request de correction #10748 : https://github.com/vatesfr/xen-orchestra/pull/10748 (vérifié le 11 novembre 2026)
  • Commit de correction 50166fe3 : https://github.com/vatesfr/xen-orchestra/commit/50166fe3a49c02069d35ba9046ca4a1f77f4e11d (vérifié le 11 novembre 2026)
  • authentication.mjs vulnérable au commit parent : https://github.com/vatesfr/xen-orchestra/blob/724402733b2381d93372db0183e21df9d2c457f7/packages/xo-server/src/xo-mixins/authentication.mjs (vérifié le 11 novembre 2026)
  • rest-api.mjs vulnérable au commit parent : https://github.com/vatesfr/xen-orchestra/blob/724402733b2381d93372db0183e21df9d2c457f7/packages/xo-server/src/xo-mixins/rest-api.mjs (vérifié le 11 novembre 2026)
  • Dépôt Xen Orchestra : https://github.com/vatesfr/xen-orchestra (vérifié le 11 novembre 2026)
  • Image de conteneur communautaire Xen Orchestra : https://hub.docker.com/r/ronivay/xen-orchestra (vérifié le 11 novembre 2026)