- 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
1 commentaires
Réactions sur Hacker News
Cela revient à faire en sorte que l’en-tête de sécurité critique défini par un service d’authentification interne inclue aussi une chaîne arbitraire fournie par l’utilisateur final via
git push -oc’est facile à dire après coup, mais là, c’est quand même complètement aberrant
L’approche de reverse engineering assisté par l’IA montre bien les points forts actuels des agents LLM
comme ce sont des modèles énormément entraînés sur du code, ils peuvent fortement accélérer la compréhension des entrailles de systèmes complexes
la recherche en sécurité consiste souvent à la fois à 1) comprendre des mécanismes internes compliqués et 2) y trouver une vulnérabilité,
et il arrive souvent qu’une fois le vrai mécanisme interne révélé, la vulnérabilité elle-même devienne étonnamment facile à voir
CVE-2026-3854 n’était pas un cas immédiatement obvious même en connaissant l’interne,
mais si cette injection de commande avait été exposée sur une surface d’attaque plus traditionnelle ou plus accessible, elle aurait probablement été découverte très vite
mais ces derniers temps, on a l’impression que cet élan s’est un peu brouillé, ou qu’il est volontairement freiné par ceux qui veulent préserver le lock-in dev/vendor créé par la complexité syntaxique du C++
On dirait presque qu’il y a quelqu’un de Wiz ici, tellement le résultat semble solide
le produit tient encore plutôt bien malgré une croissance extrême et une inflation de fonctionnalités,
et l’équipe sécurité trouve régulièrement des choses vraiment intéressantes
osv-scannerettrivypour ne regarder que le critiquealors qu’en revanche, pour des opérations un peu suspectes comme interroger un DC en CLI et réinitialiser des identifiants, silence radio, ce qui est assez frustrant
Quand
babeldrelaie une requête push, il place les push options dans l’en-tête X-Stat de la requête interne,et cette valeur est une chaîne arbitraire fournie par l’utilisateur via
git push -osauf qu’ils ont copié la valeur telle quelle sans assainir les points-virgules,
or
;sert de séparateur de champs dans X-Stat, ce qui permet de sortir du champ d’origine et de créer de nouveaux champs contrôlés par l’attaquantc’est vraiment le niveau de l’erreur la plus basique possible, au point que le fruit semblait si bas qu’il était enterré sous terre
Même si la vulnérabilité a été détectée avant toute exploitation connue,
je me demande s’il était nécessaire d’alimenter la panique avec des formulations comme BREAKING, unauthorized access ou millions of repositories
https://x.com/wiz_io/status/2049153209982140718
GitHub a simplement eu de la chance que ce soit le fuzzing de Wiz qui tombe dessus, et non un acteur étatique
Le fait que 88 % des instances GHES n’aient toujours pas appliqué un correctif de sécurité critique publié il y a 7 semaines paraît assez grave
https://docs.github.com/en/enterprise-server@3.19/admin/release-notes#3.19.3
appliquer ne serait-ce qu’une release de patch nécessite plusieurs heures d’indisponibilité,
et il n’existe même pas de méthode de mise à niveau HA officiellement supportée, ce qui empêche même les clients consciencieux de suivre rapidement les dernières versions
quand on se plaint, on nous dit de migrer vers GitHub Enterprise Cloud,
mais on peut se demander combien de gens accepteraient cela aussi facilement dans le contexte actuel
cela dit, GHES a au moins un avantage : il ne tombe pas pendant les pannes quotidiennes de github.com
et semble vouloir programmer la mise à niveau à une date avec peu d’impact opérationnel
en revanche, si l’instance est publique, il faut la mettre à jour immédiatement
avec les informations de l’article et le code source public de GitHub Enterprise, il ne semble pas difficile de reconstituer une méthode de reproduction
ou suivre le planning prévu en espérant qu’il n’arrive rien ; en général, c’est la seconde option qui l’emporte
voir un produit on-prem n’être mis à jour qu’une fois par an n’a rien d’étonnant
sur les logiciels d’entreprise avec beaucoup de données, il suffisait souvent d’un détail mineur pour casser l’installation et forcer l’équipe ops à revenir en arrière
les anciennes mises à niveau de SharePoint donnaient presque l’impression de lancer les dés
C’est encore un gros succès pour Wiz,
et on a l’impression d’un moment charnière qui montre à quel point les outils IA poussent le RE et la découverte de chemins de compromission
c’est un point de donnée supplémentaire montrant qu’en sécurité, on ne doit pas s’appuyer sur la security through obscurity
Tout le monde parle de remplacer GitHub, mais il reste la question de savoir par quoi
si même un acteur comme GitHub finit par sortir une RCE, il est difficile d’affirmer sereinement qu’une autre alternative fera mieux
https://news.ycombinator.com/item?id=46961345
https://news.ycombinator.com/item?id=47712656
et d’utiliser GitHub uniquement comme miroir tant qu’on profite du CI gratuit
les secrets peuvent être confiés à un fournisseur d’hébergement de secrets séparé
j’ai encore du mal à croire que Forgejo soit devenu aussi réactif et GitHub aussi lent
les projets internes sont hébergés sur une instance Forgejo privée, et les projets publics sont publiés sur GitHub tout en étant répliqués vers Forgejo
j’ai été surpris de voir à quel point Forgejo est essentiellement un binaire unique facile à configurer,
et comme tous nos services internes pointent vers Forgejo, quitter GitHub un jour causerait peu de friction
une image Docker tout-en-un et quelques GitLab runners suffisent largement pour des équipes petites à moyennes,
et il n’y a aucune raison de se compliquer la vie avec la version Kubernetes à moins d’en avoir réellement besoin
C’était déjà impressionnant de voir une IA trouver des vulnérabilités dans du code source,
mais le faire jusque dans des exécutables binaires est vraiment stupéfiant
le potentiel est énorme, pour le meilleur comme pour le pire
et, encore une fois, cela rappelle qu’il ne faut pas traiter des données comme des commandes
toutes les entrées utilisateur doivent être assainies
donc le fait qu’il soit bon en source-to-source ou text-to-source n’avait rien de surprenant,
et il n’est peut-être pas si étonnant non plus qu’il s’adapte bien à la compréhension d’une version asm
cela reste malgré tout impressionnant
Je me demande s’il sera possible de déterminer si cela a réellement été exploité
les logs HTTP/git permettront peut-être de vérifier dans une certaine mesure s’il y a eu exploitation,
mais il est possible qu’ils ne permettent pas de savoir exactement à quoi l’attaquant a accédé ni qui l’a fait
si l’exploit pouvait s’exécuter de manière autonome sur le serveur git, alors par définition il pouvait échapper à la journalisation