- Un défaut du protocole interne sur le chemin
git pushsuffisait à permettre une exécution de code à distance sur le backend ; GitHub.com a déjà été atténué, mais GHES doit recevoir le correctif - Une push option, entrée contrôlée par l’utilisateur, était recopiée telle quelle dans l’en-tête
X-Stat, ce qui permettait d’injecter un nouveau champ avec un simple point-virgule ; le comportement last-write-wins, où la dernière valeur d’une même clé écrase la précédente, a été exploité - En combinant parmi les champs injectables
rails_env,custom_hooks_diretrepo_pre_receive_hooks, il était possible de contourner le sandbox et d’exécuter des hooks depuis un chemin choisi par l’attaquant avec les privilèges de l’utilisateurgit - Le même mécanisme permettait aussi d’injecter le flag enterprise mode de GitHub.com, confirmant une exécution de code sur un shared storage node, puis un état permettant de lire les dépôts d’autres utilisateurs et organisations présents sur ce nœud
- Cela montre que, dans une architecture multiservice où différents services se fient à un format partagé, l’absence de nettoyage des entrées, un chemin d’exécution non productif et l’absence de validation des chemins peuvent se combiner pour produire une vulnérabilité majeure
Réponse immédiate et périmètre d’impact
- Sur GitHub.com, le problème a déjà été atténué et aucune action supplémentaire n’est nécessaire
- GitHub Enterprise Server nécessite une intervention immédiate ; il faut mettre à niveau vers GHES 3.19.3 ou supérieur, qui inclut le correctif de
CVE-2026-3854 - La plage de versions vulnérables est GHES 3.19.1 et antérieures ; les versions corrigées indiquées sont
3.14.24,3.15.19,3.16.15,3.17.12,3.18.6,3.19.3 - Au moment de la rédaction, 88 % des instances GHES étaient encore vulnérables
- Les informations techniques complémentaires et les procédures de remédiation de GitHub sont disponibles sur le blog sécurité de GitHub
- Les clients Wiz peuvent identifier les instances GHES vulnérables avec les requêtes préconstruites du Wiz Threat Center
Contexte de l’enquête et approche
- L’infrastructure git interne de GitHub traite tout le flux
git push, au travers de plusieurs services internes écrits dans différents langages de programmation - Dans ce type de structure multiservice, les différences de façon dont chaque composant analyse et approuve les données partagées peuvent devenir des vulnérabilités
- Jusqu’ici, extraire et auditer la grande quantité de binaires compilés en boîte noire constituant ce pipeline demandait un temps considérable et beaucoup de travail manuel
- Des outils augmentés par l’IA et une rétro-ingénierie automatisée basée sur
IDA MCPont permis d’analyser rapidement les binaires compilés et de reconstituer le protocole interne - Au cours du processus, les points où une entrée utilisateur influence le comportement du serveur tout au long du pipeline ont été suivis de manière systématique, ce qui a permis d’identifier un défaut fondamental dans l’ensemble du flux d’entrée
Architecture interne et frontières de confiance
- Lorsqu’un
git pusharrive via SSH, la requête suit le fluxbabeld,gitauth,gitrpcd, puis le pre-receive hook babeldest le point d’entrée de toutes les opérations git ; il reçoit la connexion SSH, puis transmet l’authentification àgitauthgitauthvérifie les identifiants de l’utilisateur et ses droits de push sur le dépôt, puis renvoie des politiques de sécurité comme les limites de taille de fichier ou les règles de nommage de branche- Sur cette base,
babeldconstruit l’en-tête interneX-Statcontenant des métadonnées de sécurité gitrpcdreçoit l’en-têteX-Statpour configurer l’environnement des processus suivants et fait totalement confiance àbabeldsans authentification propre- Le pre-receive hook vérifie, avant l’acceptation du push, les limites de taille de fichier, les règles de nommage de branche, l’intégrité LFS et les hooks personnalisés définis par les administrateurs
- Le lien central était l’en-tête X-Stat, qui contient des paires
key=valueséparées par; - Les services internes découpent
X-Statsur;puis remplissent une map ; lorsqu’une même clé apparaît deux fois, la valeur la plus récente écrase la précédente selon la règle last-write-wins babeldajoute aussi àX-Statles push options transmises viagit push -o, sous des champs commepush_option_0,push_option_1etpush_option_count
Cause de la vulnérabilité : injection de champs X-Stat
babeldcopiait dans l’en-têteX-Statla valeur de push option, contrôlée par l’utilisateur, sans nettoyer les points-virgules- Comme
;est le séparateur de champs deX-Stat, un seul point-virgule dans une push option permettait de sortir du champ d’origine et de créer un nouveau champ contrôlé par l’attaquant - Par exemple, en injectant
large_blob_rejection_enabled=bool:falsedanspush_option_0, la valeurbool:truedéfinie plus tôt se retrouvait écrasée par la valeur plus tardive - Ce comportement a été confirmé à la fois par l’analyse des binaires et par des captures réseau sur une instance GHES réelle
- La combinaison de rétro-ingénierie et d’analyse au niveau du trafic a permis de cartographier les champs
X-Statinjectables - Les champs particulièrement sensibles côté sécurité identifiés étaient
rails_env,custom_hooks_dir,repo_pre_receive_hooks,large_blob_rejection_enabled,reject_sha_like_refs,user_operator_mode - Parmi eux, les trois champs
rails_env,custom_hooks_diretrepo_pre_receive_hooksétaient au cœur de la chaîne menant à l’exécution de code à distance
La chaîne menant au RCE sur GHES
- GHES prend en charge les custom pre-receive hooks, exécutés avant l’acceptation d’un push
- Le binaire pre-receive comportait deux chemins d’exécution qui ne différaient que par la valeur
rails_envissue deX-Stat - Si la valeur était
production, le hook s’exécutait dans un sandbox ; pour toute autre valeur, il s’exécutait directement avec les privilèges de l’utilisateur de servicegit, sans sandbox ni isolation - Injecter une valeur non productive dans
rails_envpermettait donc de contourner le sandbox - Ensuite, l’injection de
custom_hooks_dirdonnait à l’attaquant le contrôle du répertoire de base dans lequel le script de hook était recherché - Enfin, en injectant dans
repo_pre_receive_hooksune définition de hook contenant une traversée de chemin, la résolution de chemin du binaire combinait le répertoire contrôlé par l’attaquant et la charge de traversée pour pointer vers un chemin arbitraire du système de fichiers - Le chemin d’exécution non productif lançait alors directement ce chemin résolu, sans argument, sans sandbox et sous l’utilisateur de service
git - Lors de la validation réelle, une seule commande
git pusha renvoyé la sortieuid=500(git), confirmant un RCE avec les privilèges de l’utilisateurgit - Avec ces privilèges, il était possible d’obtenir un contrôle total sur l’instance GHES, y compris la lecture et l’écriture sur le système de fichiers ainsi que la visibilité sur la configuration des services internes
Extension à GitHub.com et exposition inter-locataires
- Lorsque la même chaîne d’exploitation a été appliquée à un dépôt GitHub.com, le push réussissait d’abord, mais les custom hooks ne s’exécutaient pas
- En injectant
user_operator_mode=bool:trueet en comparant les sorties de débogage des deux plateformes, il est apparu que GitHub.com n’atteignait pas le chemin de code des custom hooks - Une rétro-ingénierie complémentaire a montré qu’un booléen contrôlant le comportement enterprise mode du serveur existait dans l’en-tête
X-Stat - Sur GHES, ce flag vaut true par défaut, ce qui active toujours le chemin des custom hooks ; sur GitHub.com, la valeur par défaut est false, ce qui empêche normalement d’atteindre ce chemin
- Comme ce flag pouvait lui aussi être injecté via le même mécanisme, l’ajout d’un champ supplémentaire rendait la chaîne d’exploitation complète fonctionnelle sur GitHub.com également
- Ensuite, le résultat de l’exécution de
hostnamea été renvoyé depuis l’infrastructure GitHub.com, confirmant un RCE sur GitHub.com - GitHub.com est une plateforme multitenant, où les dépôts de multiples utilisateurs et organisations sont stockés sur une infrastructure backend partagée
- L’exécution de code a eu lieu sur un shared storage node ; à cet endroit, l’utilisateur
gitdispose de larges permissions sur le système de fichiers afin de traiter toutes les opérations sur les dépôts présents sur le nœud - Si cet utilisateur est compromis, les dépôts d’autres organisations et utilisateurs présents sur le nœud peuvent eux aussi être lus, indépendamment de leur propriétaire
- L’énumération des entrées d’index des dépôts accessibles sur les deux nœuds compromis a montré des millions d’entrées par nœud, incluant des dépôts d’autres utilisateurs et organisations
- Le contenu réel des dépôts d’autres locataires n’a pas été consulté ; seuls des comptes de test internes ont été utilisés pour vérifier que les permissions système de l’utilisateur
gitautorisaient la lecture de tous les dépôts du nœud
Enseignements clés et calendrier de divulgation
- Un simple
git pushsuffisait à exploiter un défaut du protocole interne pour obtenir une exécution de code à distance sur l’infrastructure backend - Quand plusieurs services écrits dans différents langages s’échangent des données via un protocole interne partagé, les hypothèses de confiance de chaque service deviennent elles-mêmes une surface d’attaque
- Dans cette chaîne, un service insérait tel quel la valeur d’une push option, un autre faisait confiance à tous les champs de
X-Stat, et le pre-receive hook supposait qu’en productionrails_envseraitproduction - Les chemins de code non productifs au sein des binaires de production, l’absence de validation contre la traversée de chemin dans les scripts de hook et l’absence de nettoyage des entrées dans un protocole fondé sur des délimiteurs sont des schémas qui peuvent exister dans d’autres bases de code
- Les équipes qui exploitent des architectures multiservices doivent particulièrement vérifier comment des entrées contrôlées par l’utilisateur circulent dans les protocoles internes, surtout lorsque des paramètres sensibles pour la sécurité dérivent de formats de données partagés
- Dans cette recherche, des outils de rétro-ingénierie augmentée par l’IA, dont
IDA MCP, ont permis d’accélérer fortement l’analyse de binaires compilés et la reconstitution de protocoles internes - À mesure que ces outils gagnent en maturité, ils devraient jouer un rôle croissant dans l’identification de classes de vulnérabilités nécessitant une analyse inter-composants approfondie
- D’après le calendrier de divulgation, la vulnérabilité d’injection de push option dans X-Stat a été découverte le
2026-03-04; le même jour, le RCE a été confirmé surGHES 3.19.1, signalé à GitHub, et le correctif GitHub.com a été déployé - Le
2026-03-10, CVE-2026-3854 et un CVSS 8.7 ont été attribués, puis le correctif GHES a été publié - Le
2026-04-28, la vulnérabilité a été rendue publique
Aucun commentaire pour le moment.