Le 21 octobre 2026, GitLab corrige CVE-2026-110264, une exécution de code à distance sans authentification notée 10.0 qui touche toutes les versions de GitLab CE et EE depuis la 7.0, y compris les instances mises à jour le 12 octobre. L'éditeur ne propose aucun contournement. Découvrez comment vérifier votre version, choisir la bonne cible de mise à jour et rechercher des traces de tentatives d'exploitation.
Depuis le 23 septembre, GitLab a corrigé en deux patchs trois failles critiques liées à son moteur d’expressions régulières, toutes signalées par le même chercheur, joaxcar, via son programme de bug bounty sur HackerOne. Le 21 octobre, une quatrième s’ajoute à la série et change d’échelle : CVE-2026-110264, notée 10.0 en CVSS 3.1, permet sous certaines conditions à un attaquant non authentifié d’exécuter du code sur le serveur, et touche toutes les versions de GitLab CE et EE depuis la 7.0, sortie en 2014. GitLab a publié le même jour sept versions corrigées, dont quatre rétroportages sur des branches qui sortent de sa politique de support habituelle, une mesure qu’il réserve aux failles les plus graves.
Mettez à jour vers 19.5.1, 19.4.3, 19.3.6, 19.2.9, 19.1.9, 19.0.10 ou 18.11.13. Une instance mise à jour le 12 octobre (19.4.2, 19.3.5 ou 19.2.8) est de nouveau vulnérable, puisque la version corrigée se situe un cran au-dessus. L’avis de GitLab ne propose aucun contournement. Seules les installations auto-hébergées (self-managed) doivent agir : GitLab.com est déjà corrigé, tout comme les instances GitLab Dedicated en 19.3.5-internal0, 19.4.2-internal0 ou au-delà.
Ce type d’avis appelle une procédure de vérification standard, que nous déroulons ici dans l’ordre : état des correctifs, compréhension de la faille, mise à jour, puis recherche de traces dans les journaux.
État des correctifs
Tous les canaux de distribution ont reçu les versions corrigées le 21 octobre. Relevé effectué le 21 octobre à 22h30 (heure de Paris).
| Canal | Statut |
|---|---|
| GitLab.com | Corrigé |
| GitLab Dedicated | Corrigé à partir de 19.3.5-internal0 et 19.4.2-internal0 |
| Paquets Omnibus (apt, dnf) | Disponibles |
Images Docker gitlab/gitlab-ce et gitlab/gitlab-ee | Disponibles, publiées entre 17h01 et 19h40 |
Chart Helm gitlab/gitlab | Disponible : 10.5.1, 10.4.3, 10.3.7, 10.2.9, 10.1.9, 10.0.10 et 9.11.14 |
| Fiche CVE.org et NVD | Pas encore publiée |
| Catalogue CISA KEV | Absente (version 2026.10.21) |
| CERT-FR | Aucun avis GitLab publié au moment du relevé |
| CERT-EU | Pas de nouvel avis, le 2026-016 couvre le correctif du 12 octobre |
L’avis de GitLab ne dit rien d’une éventuelle exploitation. The Hacker News indique que l’éditeur ne signale aucune attaque, ce qui concorde avec l’absence de la CVE dans le catalogue KEV.
Comprendre la faille
Ce que dit l’avis officiel
L’avis décrit un dépassement d’entier lors de la compilation d’une expression régulière spécialement construite, qui peut, « sous certaines conditions », permettre à un utilisateur non authentifié d’exécuter du code arbitraire sur le serveur. Le vecteur CVSS (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) résume la gravité : exploitable à distance, sans compte, sans interaction et avec un impact maximal. Les conditions d’exploitation ne sont pas détaillées dans l’avis.
Ce que précise la documentation de détection de GitLab
L’équipe sécurité de GitLab a publié en parallèle deux règles de détection au format Sigma dans son dépôt open source TLDR, et leur documentation va plus loin que l’avis. Le point d’entrée est le rendu des fichiers Org-mode (.org), assuré par la gem org-ruby : le mot-clé déclaré sur une ligne #+TODO: du fichier est injecté tel quel dans une seconde expression régulière. Au-delà de 32 767 répétitions, le moteur Onigmo de Ruby attribue à la répétition un identifiant qui dépasse la limite d’un entier signé sur 16 bits, ce qui provoque une écriture hors limites au moment de la correspondance. Avec une préparation du tas, cette écriture devient un appel system() exécuté sous l’utilisateur git.
Selon cette même documentation, l’attaque ne nécessite aucune authentification, seulement un projet public capable d’héberger le fichier .org, et la prévisualisation de l’éditeur permet aussi de forcer le moteur de rendu Org sur n’importe quel fichier. Une exploitation réussie expose le fichier gitlab-secrets.json, toutes les variables CI/CD, les tokens de runners et d’accès, ainsi que l’ensemble des dépôts de l’instance. Ces éléments ne figurent pas dans l’avis et GitLab ne les présente pas comme des mesures de contournement : ils servent à comprendre les journaux, pas à décider de reporter la mise à jour.
Vérifier votre version
# Installation Omnibus (paquet Linux)
cat /opt/gitlab/embedded/service/gitlab-rails/VERSION
# Conteneur Docker (adapter le nom du conteneur)
docker exec gitlab cat /opt/gitlab/embedded/service/gitlab-rails/VERSION
# Chart Helm : version du chart et de l'application
helm list -n gitlab
Comparez ensuite le résultat à la version cible de votre branche :
| Version installée | Version cible |
|---|---|
| 19.5.x | 19.5.1 |
| 19.4.x | 19.4.3 |
| 19.3.x | 19.3.6 |
| 19.2.x | 19.2.9 |
| 19.1.x | 19.1.9 |
| 19.0.x | 19.0.10 |
| 18.11.x | 18.11.13 |
| Antérieure à 18.11 | Passage par les upgrade stops, jusqu’à 18.11.13 au minimum |
Le tableau repris par la presse associe « 7.0 à 18.11 » à 18.11.13, mais une instance en 17.x ou plus ancienne ne peut pas sauter directement à cette version : GitLab impose des étapes de mise à jour obligatoires (18.2, 18.5, 18.8 et 18.11 pour la série 18), et l’outil Upgrade Path calcule le chemin exact depuis votre version. Les branches 19.2, 19.1, 19.0 et 18.11 ne font plus partie de la politique de support, qui couvre la version courante et les deux précédentes (19.5, 19.4 et 19.3) : leurs rétroportages sont une étape de transit, pas une destination.
Mettre à jour
Sauvegarder avant tout
# Sauvegarde des données (dépôts, base, uploads)
sudo gitlab-backup create
# La sauvegarde n'inclut ni la configuration ni les secrets : les copier à part
sudo tar czf /root/gitlab-config-$(date +%F).tgz /etc/gitlab/gitlab.rb /etc/gitlab/gitlab-secrets.json
Installer la version corrigée
# Debian et Ubuntu (remplacer ee par ce pour l'édition Community)
sudo apt-get update
sudo apt-get install gitlab-ee=19.5.1-ee.0
# RHEL, AlmaLinux et Rocky Linux 9
sudo dnf install gitlab-ee-19.5.1-ee.0.el9
# Docker Compose : épingler le tag dans docker-compose.yml, puis
# image: gitlab/gitlab-ee:19.5.1-ee.0
docker compose pull gitlab && docker compose up -d gitlab
# Helm : réappliquer les valeurs actuelles avec le chart correspondant
helm repo update
helm get values gitlab -n gitlab > gitlab-values.yaml
helm upgrade gitlab gitlab/gitlab -n gitlab --version 10.5.1 -f gitlab-values.yaml
Les numéros de chart Helm ne suivent pas toujours ceux de GitLab : 19.3.6 correspond au chart 10.3.7, et 18.11.13 au chart 9.11.14. Les versions 19.4.3 et 19.3.6 contiennent par ailleurs des migrations de base de données exécutées pendant la mise à jour : sur une instance mono-nœud, GitLab reste indisponible jusqu’à leur fin, tandis que les architectures multi-nœuds peuvent appliquer le correctif sans interruption en suivant la procédure zero-downtime.
Une fois la mise à jour terminée, relancez la commande de vérification de version, puis sudo gitlab-rake gitlab:check SANITIZE=true pour contrôler l’état de l’instance.
Rechercher des traces de tentatives
Les deux règles publiées par GitLab, « Onigmo native worker crash » et « Org mode render error burst », s’appuient sur des journaux que toutes les instances ne collectent pas par défaut. Sans SIEM, leurs requêtes brutes s’exécutent directement sur le serveur ; les commandes ci-dessous les reprennent pour une installation Omnibus, avec zgrep pour couvrir aussi les journaux compressés par la rotation. Les répertoires de logs n’étant lisibles que par root, lancez-les depuis un shell root (sudo -i) : un simple sudo devant la commande ne suffit pas, car le shell développe les motifs *.log* avant l’élévation de privilèges.
# 1. Rafales de timeouts de rendu sur des fichiers .org, comptées par client
# (cinq ou plus depuis un même client en 30 minutes déclenchent l'alerte GitLab)
zgrep -h '"exception.class":"Timeout::Error"' /var/log/gitlab/gitlab-rails/exceptions_json.log* \
| grep '"extra.class_name":"OtherMarkup"' | grep -E '"extra.file_name":"[^"]*\.org"' \
| grep -o '"meta.client_id":"[^"]*"' | sort | uniq -c | sort -rn
# 2. Prévisualisation forçant le rendu Org sur un fichier qui n'en est pas un
zgrep -h 'Projects::BlobController#preview' /var/log/gitlab/gitlab-rails/production_json.log* \
| grep '"file_path"' | grep -E '\.org"'
# 3. Crash natif d'un worker Puma dans org-ruby ou dans le moteur Onigmo
zgrep -h -A20 '\[BUG\]' /var/log/gitlab/puma/puma_stderr.log* \
| grep -E 'org-ruby|headline\.rb|regexp_helper\.rb|regexp_matcher\.rb|match_at|onig_search_gpos|onig_compile|compile_tree|compile_length_tree|rb_str_sub_bang'
La première requête isole les Timeout::Error levées par le moteur de rendu OtherMarkup sur des fichiers .org : une attaque en produit une rafale depuis un même client, identifié par ip/<adresse> lorsqu’il n’est pas authentifié. La deuxième repère toute prévisualisation dont le paramètre file_path se termine en .org, un cas que GitLab juge suspect dès la première occurrence. La troisième cherche un rapport de crash [BUG] de Ruby dont la pile passe par org-ruby ou Onigmo, et couvre aussi les failles précédentes de la série, qui passaient par les expressions régulières de la configuration CI/CD.
La documentation de GitLab suggère enfin de rechercher la charge utile elle-même, une ligne #+TODO: anormalement longue dans un fichier .org. Sa commande vise une copie de travail ; sur le serveur, les dépôts sont stockés sans copie de travail, d’où l’adaptation suivante pour le chemin Omnibus par défaut :
# Nécessite un client git sur le serveur ; s'exécute sous l'utilisateur git
sudo -u git bash <<'EOF'
cd /var/opt/gitlab/git-data/repositories || exit 1
find @hashed -maxdepth 3 -name '*.git' | while read -r repo; do
refs=$(git --git-dir="$repo" for-each-ref --format='%(refname)' refs/heads refs/tags)
[ -n "$refs" ] && git --git-dir="$repo" grep -E '^#\+(TODO|SEQ_TODO|TYP_TODO):' $refs -- '*.org' 2>/dev/null \
| awk -v r="$repo" 'length($0) > 500 { print r ": " substr($0, 1, 120) }'
done
EOF
Le script parcourt les dépôts nus du stockage haché d’Omnibus, cherche les lignes #+TODO: dans les fichiers .org de toutes les branches et de tous les tags, puis ne conserve que celles qui dépassent 500 caractères, en affichant le dépôt, la référence et le fichier concernés.
Une absence de résultat ne prouve rien : GitLab précise qu’une exploitation réussie peut rester silencieuse, sans crash ni timeout. Un résultat positif se traite en revanche comme une tentative d’exécution de code, avec la procédure de réponse à incident de l’organisation et la rotation des secrets exposés (variables CI/CD, tokens de runners et d’accès).
Une série qui appelle une organisation
| Date | CVE | Score | Accès requis | Versions touchées |
|---|---|---|---|---|
| 23 septembre | CVE-2026-93577, CVE-2026-89078 | 9.9 | Compte authentifié, via une configuration CI/CD | 19.2 à 19.4 |
| 12 octobre | CVE-2026-97229 | 10.0 | Aucun | 19.2 à 19.4 |
| 21 octobre | CVE-2026-110264 | 10.0 | Aucun | 7.0 à 19.5 |
La série ne traduit pas une négligence ponctuelle, mais une surface d’attaque structurelle : chaque fonctionnalité qui compile une expression régulière issue d’une donnée utilisateur hérite des défauts mémoire d’Onigmo, le moteur écrit en C intégré à Ruby. Les trois premières failles passaient par les expressions régulières de la configuration CI/CD ; la quatrième atteint le même moteur par un autre chemin, le rendu des fichiers Org-mode, et l’avis fait remonter la plage affectée jusqu’à la version 7.0. GitLab corrige d’ailleurs Ruby lui-même dans ses paquets : les notes de version de chaque branche mentionnent un correctif du moteur d’expressions régulières de Ruby.
Pour une équipe qui exploite une instance auto-hébergée, la conséquence est opérationnelle : trois correctifs critiques en un mois imposent une chaîne de mise à jour capable de suivre ce rythme, avec des versions épinglées, une sauvegarde systématique et une veille sur le flux RSS des patch releases. Le précédent du 10 septembre le rappelle : CVE-2026-85706, une traversée de répertoire sans authentification également notée 10.0, a été ajoutée au catalogue KEV de la CISA dès le lendemain de sa publication.
Avant : une instance corrigée le 12 octobre, considérée comme à jour, et pourtant exposée à une exécution de code sans authentification. Après : la version corrigée de sa branche installée, les journaux passés au crible des règles de GitLab et une chaîne de mise à jour prête pour le prochain correctif.
Sur une faille notée 10.0 sans contournement disponible, la seule protection certaine reste la mise à jour, et la seule question utile est de savoir combien de temps il faut à votre instance pour l’appliquer.
