CVE-2026-97229 : l’incident GitLab expliqué
Découvrez comment l’exploitation de CVE-2026-97229 a visé GitLab chez Alpine Linux, ce qui a pu être exposé et les mesures utiles pour sécuriser votre instance.
Incident GitLab chez Alpine Linux : ce que révèle la tentative d'exploitation de CVE-2026-97229
Un correctif publié ne suffit pas, à lui seul, à protéger tous les serveurs. L'incident survenu chez Alpine Linux en octobre 2026 le montre clairement : un attaquant a tenté d'exploiter CVE-2026-97229 sur l'instance GitLab d'Alpine, alors que le défaut avait déjà été corrigé dans certaines versions. Mais la mise à niveau de GitLab n'a pas fermé la faille dans l'environnement réellement utilisé par Alpine.
L'équipe n'a pas trouvé de preuve que l'attaque ait mené à l'exécution de code ou à la modification de dépôts et de paquets. En revanche, des journaux manquaient, et une exploitation réussie aurait pu rester discrète. Alpine a donc traité le serveur comme potentiellement compromis : arrêt de l'accès public et reconstruction de l'instance. Au passage, les vérifications menées sur les publications Alpine donnent des enseignements concrets aux équipes qui exploitent GitLab, Ruby et des chaînes de livraison logicielle.
Cet article détaille le déroulement de l'incident, explique pourquoi une mise à niveau « standard » n'a pas résolu le problème, sépare les faits des zones d'incertitude, et propose une méthode de réaction utilisable dans une infrastructure réelle.
Ce qui s'est passé sur GitLab
Une faille critique dans le traitement des expressions régulières
CVE-2026-97229 est une vulnérabilité critique, notée 10,0 sur l'échelle CVSS, liée à la manière dont GitLab évalue certaines expressions régulières dans la configuration d'intégration continue. Le problème se situe dans Onigmo, le moteur d'expressions régulières intégré à Ruby.
Le point à retenir : le risque ne se limite pas à une fonction propre à GitLab. Un programme qui compile des expressions régulières fournies par une source non fiable peut se retrouver avec le même type de problème. Ensuite, selon le contexte d'usage, l'impact peut aller du déni de service à une exploitation plus sérieuse.
GitLab a publié des versions corrigées le 12 octobre 2026. Mais le correctif s'appuyait sur des modifications apportées à la version de Ruby incluse dans ses paquets et images officiels. La correction a ensuite été publiée en amont dans Ruby, avec les versions 3.3.13, 3.4.12 et 4.0.9, le 23 octobre.
Une tentative ciblée, pas juste des requêtes automatisées
Les 20 et 21 octobre, un compte créé récemment a envoyé à l'instance Alpine des configurations CI conçues pour déclencher la vulnérabilité. À ce moment-là, le serveur utilisait GitLab 19.3.4, sans le correctif sorti le 12 octobre. Ces tentatives ont provoqué huit plantages des processus de travail GitLab. Dans quatre cas, l'attaquant semble avoir avancé avant d'échouer à l'étape suivante.
L'attaquant a aussi téléchargé l'image conteneur de GitLab utilisée par Alpine. Ce choix suggère une adaptation de ses essais à la construction exacte du serveur, plutôt qu'une attaque « générique ». C'est un indice de ciblage, mais ça ne prouve pas à lui seul que l'intrusion a abouti.
Les 25 et 26 octobre, de nouvelles tentatives ont échoué. Alpine a bloqué le compte le 23 octobre, puis a fermé l'accès public à GitLab le 27 octobre et lancé une reconstruction complète, achevée le 28 octobre. Les mots de passe ont été réinitialisés et les clés secrètes de GitLab remplacées.
Un incident à traiter comme une compromission possible
L'équipe n'a trouvé aucun signe que du code hostile ait été exécuté. Aucun fichier, aucune clé, aucun hook et aucun processus inattendu, et pas de délai anormal lors de tests destinés à détecter l'exploitation. Les requêtes web et API consultables ne montrent pas non plus de données privées renvoyées à l'attaquant.
Mais une absence de preuve ne suffit pas quand la journalisation est incomplète et qu'une exploitation peut rester furtive. Alpine a donc choisi la voie la plus prudente : considérer l'instance comme potentiellement compromise, supprimer l'environnement et le reconstruire, plutôt que compter uniquement sur une mise à jour.
Pourquoi GitLab 19.3.6 n'a pas suffi
Le correctif se trouvait dans Ruby, pas seulement dans GitLab
Le 22 octobre, Alpine a mis à niveau GitLab vers 19.3.6, dans l'idée de corriger le problème. Cette mise à niveau n'a toutefois pas éliminé la vulnérabilité dans l'image réellement utilisée. La différence vient de l'assemblage du logiciel : le correctif publié pour GitLab dépendait d'un correctif Ruby intégré à certains paquets officiels, alors que l'image Alpine contenait une version standard de Ruby, sans ce composant corrigé.
C'est facile à rater en pratique. On peut avoir « une version d'application à jour » tout en conservant une dépendance embarquée encore vulnérable. Le 26 octobre, Alpine a constaté que l'instance restait exposée malgré la mise à niveau de GitLab. L'accès public a ensuite été fermé le lendemain.
La leçon n'est pas que mettre GitLab à jour ne sert à rien. La leçon, c'est de vérifier ce qui tourne vraiment, pas seulement ce que le service affiche. Une image personnalisée, une compilation depuis des sources, ou un paquetage différent de celui attendu peuvent changer la réalité du correctif.
Ce que les administrateurs doivent vérifier
Si vous exécutez GitLab avec votre propre version de Ruby (compilée depuis les sources ou incluse dans une image personnalisée), mettre à niveau GitLab ne suffit pas. Il faut aussi vérifier que Ruby correspond à l'une des versions corrigées : 3.3.13, 3.4.12, 4.0.9 ou plus récent, selon la branche.
Pour l'image alpinelinux/gitlab, Alpine indique qu'il faut re-tirer l'étiquette 19.3.6 publiée le 27 octobre. Les images 19.3.6 téléchargées avant cette date, ainsi que les étiquettes plus anciennes, restent vulnérables. En environnement conteneurisé, une étiquette « stable » ne garantit pas que l'image locale correspond à la version reconstruite : il faut récupérer l'image à nouveau et vérifier le digest déployé.
Une manière simple et pragmatique de cadrer le contrôle :
- Quelle version de GitLab tourne réellement en production ?
- Quelle version de Ruby est embarquée dans le processus ou l'image active ?
- Le correctif est-il bien présent dans cette construction précise, et pas seulement dans une version publiée ailleurs ?
- Les environnements de test, les runners et les secours utilisent-ils eux aussi l'image corrigée ?
Ce contrôle réduit un angle mort fréquent : l'écart entre « le correctif annoncé » et « le logiciel réellement déployé ». En entreprise, cet écart se cache souvent dans une image mise en cache, un runner oublié ou un environnement restauré depuis une sauvegarde ancienne.
Ce que l'incident permet d'affirmer et ce qui reste incertain
Les éléments vérifiés par Alpine
Alpine indique n'avoir trouvé aucune modification malveillante dans le dépôt aports, les paquets, ni les publications du 21 octobre. Les versions stables 3.21.9, 3.22.7, 3.23.7 et 3.24.3, leurs images ISO et les archives minirootfs utilisées pour construire les images Docker officielles ont été examinées.
L'équipe a comparé les commits du dépôt ajoutés entre le 20 et le 22 octobre avec des traces conservées en dehors de GitLab : copies locales des développeurs et données issues de 45 machines de construction. Les paquets produits jusqu'au 24 octobre, sur les différentes architectures, correspondent aux commits publiés sur git.alpinelinux.org. Les versions datées du 21 octobre proviennent des mêmes commits vérifiés.
Les clés de signature des paquets et des publications n'étaient pas stockées sur le serveur GitLab. Selon Alpine, elles ne l'y ont jamais été. Ce point a limité le scénario le plus grave : même en cas de compromission, l'attaquant n'aurait pas automatiquement obtenu les clés nécessaires pour signer une publication officielle.
Alpine a aussi précisé que les vérifications initiales couvraient les commits du 20 au 22 octobre et les paquets construits jusqu'au 24. Puisque GitLab est resté vulnérable jusqu'à sa fermeture, l'équipe a étendu ces contrôles jusqu'au 27 octobre. En clair : toute vérification doit se lire avec ses dates et son périmètre.
Pourquoi l'incertitude n'a pas pu être levée
Un exploit réussi aurait pu ne rien faire de spectaculaire : pas forcément de plantage, et pas forcément de traces visibles dans les journaux web disponibles. Certains journaux liés aux tâches d'arrière-plan avaient disparu, tout comme le système de fichiers du conteneur précédent. L'instance ne conservait pas non plus de traces des connexions réseau sortantes, et l'hébergeur n'en disposait pas non plus.
Ces manques empêchent de conclure que l'attaque a abouti. Ils empêchent aussi de conclure qu'elle n'a pas abouti. Il faut donc distinguer trois niveaux : ce qui a été observé, ce qui rend une compromission peu probable, et ce qui reste impossible à vérifier. Mélanger ces niveaux finit soit par minimiser le risque, soit par affirmer une compromission certaine sans preuve.
Si l'exploitation avait fonctionné, les données potentiellement accessibles auraient pu inclure des adresses électroniques, des noms et des adresses IP, des empreintes de mots de passe, des secrets d'authentification à deux facteurs, des variables CI/CD et des jetons de runners. Des identifiants de webhooks, d'intégrations et de miroirs, des jetons d'accès personnels stockés sous forme d'empreintes, ainsi que des dépôts privés et des contenus confidentiels auraient aussi pu être concernés.
Pour les utilisateurs, Alpine a demandé de changer tout mot de passe réutilisé ailleurs. La raison est directe : l'équipe a vu des tentatives de connexion automatisées à GitLab en s'appuyant sur des mots de passe divulgués lors d'incidents sur d'autres services. La réutilisation transforme une fuite « ailleurs » en risque immédiat pour les comptes concernés.
Quelles mesures retenir pour votre instance GitLab
Prioriser le confinement et la vérification
Quand une vulnérabilité critique est testée contre votre instance, la première décision n'est pas forcément de remettre le service en ligne au plus vite. Le bon réflexe, c'est de déterminer si vous avez suffisamment d'éléments pour définir le périmètre de l'incident. Si les journaux nécessaires n'existent plus, reconstruire peut être plus fiable qu'un nettoyage ciblé, même si cela prend plus de temps et impacte la disponibilité.
Une séquence de réponse raisonnable :
- Restreindre l'accès public ou isoler les composants vulnérables.
- Conserver les journaux, les images, les disques et les métadonnées disponibles avant toute opération qui les écrase.
- Vérifier la version de GitLab, Ruby et des dépendances réellement exécutées.
- Comparer le contenu des dépôts et des artefacts à des sources indépendantes du serveur concerné.
- Réinitialiser les secrets potentiellement exposés : mots de passe, jetons, variables CI/CD et clés d'intégration.
- Reconstruire l'instance depuis une base connue, puis valider avant de rouvrir.
Toutes les organisations n'ont pas besoin d'une reconstruction complète à chaque alerte. Le choix dépend de la preuve disponible, de la valeur des données et du coût d'une compromission silencieuse. Dans le cas d'Alpine, l'absence de journaux suffisants et les tentatives d'exploitation observées justifiaient une réponse plus lourde.
Réduire les angles morts avant le prochain incident
Alpine a annoncé plusieurs changements : exécuter une version corrigée de Ruby, appliquer les mises à jour de sécurité critiques de GitLab dans la journée, vérifier si elles dépendent aussi de correctifs Ruby ou d'autres composants, et conserver les journaux plus longtemps.
L'équipe prévoit aussi de journaliser les connexions sortantes du serveur GitLab et les connexions à la base de données. Dans les enquêtes, ces informations font souvent la différence : elles aident à comprendre ce qu'un processus a pu faire après une exploitation. Garder les journaux au-delà de 14 jours augmente aussi les chances de reconstituer une chronologie, à condition qu'ils soient protégés contre toute modification par le serveur analysé.
Enfin, Alpine veut signer les étiquettes de publication afin qu'elles puissent être vérifiées indépendamment de GitLab. C'est un bon garde-fou : la plateforme de développement ne devrait pas être la seule « source de confiance » pour vérifier ce qui en sort.
Pour les paquets Ruby d'Alpine, la distribution indique que les branches 3.22, 3.23, 3.24 et edge livrent Ruby 3.4.12, tandis que la branche 3.21 fournit Ruby 3.3.13. La commande apk upgrade permet d'installer les mises à jour disponibles. Dans un parc géré, l'approche recommandée reste de tester puis déployer selon votre processus, et de confirmer ensuite la version réellement installée sur les systèmes concernés.
Conclusion
L'incident chez Alpine ne prouve pas que les dépôts ou les paquets aient été compromis. Il montre surtout pourquoi on ne peut pas se contenter d'un numéro de version ou d'un statut de mise à jour : GitLab avait bien été mis à niveau, mais la version de Ruby incluse dans l'image restait vulnérable.
La réponse d'Alpine repose sur deux principes opérationnels : vérifier les artefacts à partir de sources indépendantes et reconstruire quand les preuves disponibles ne permettent pas d'écarter une compromission. Pour votre instance, commencez par l'inventaire de ce qui tourne réellement, confirmez le correctif dans les images déployées et assurez-vous que vos journaux permettront de répondre aux questions essentielles dès qu'une alerte survient.