Forgejo 16.0.4 referme un RCE critique exploitable depuis un simple dépôt modèle
La forge auto-hébergée Forgejo a publié les versions 16.0.4 et 15.0.8 le 10 septembre pour corriger un RCE critique né de l’expansion de template, accompagné de trois failles d’autorisation qui partagent la même cause racine. Tout ce qui tourne en 16.0.3 ou avant doit être corrigé, et l’inventaire des jetons à portée réduite doit être revu.
10 septembre 2026. Forgejo publie les versions 16.0.4 et 15.0.8 pour corriger CVE-2026-89094, un RCE critique déclenché par l’expansion de variables lors de la création d’un dépôt à partir d’un modèle. 16.0.3 et antérieur sont affectés. Le même lot referme trois autres failles d’autorisation qui, selon l’analyse du cabinet Reptile Haus, ne sont que le même bug portant des vêtements différents. Pour qui auto-héberge sa forge, le vrai enseignement dépasse le patch : il faut auditer par objet, pas par point d’entrée.
Un RCE construit uniquement de gestes corrects
Le mécanisme est remarquable parce qu’aucune des trois étapes n’est fautive isolément. Quand Forgejo génère un dépôt depuis un dépôt modèle, il enchaîne : cloner le modèle, supprimer son dossier .git, exécuter l’expansion de variables sur les fichiers listés dans .forgejo/template, puis lancer git init sur le résultat.
Relisez cet ordre. La suppression du .git a lieu avant l’expansion. Le git init a lieu après. Or l’expansion écrit des fichiers : si un modèle malveillant réussit à la contraindre à créer un dossier .git du contenu de son choix, le git init qui suit en trouve un déjà présent — et git init sur un dossier contenant déjà un .git n’échoue pas et ne repart pas de zéro. Il adopte ce qu’il trouve, un comportement documenté et voulu.
Un dossier .git n’est pas une donnée inerte : il porte une config et des hooks, et plusieurs clés de config désignent des programmes à exécuter. Forgejo décrit lui-même l’issue comme permettant de lire des données arbitraires de l’hôte et d’exécuter des processus arbitraires. En clair, quiconque peut publier un dépôt modèle que vos utilisateurs dupliquent obtient une exécution de code sur la machine qui héberge tous vos dépôts.
Le correctif ne change aucune des trois étapes : il supprime le .git une seconde fois, après l’expansion — combler l’écart entre un contrôle et le chemin qui passe au travers.
Trois failles d’autorisation, une seule cause racine
Le même lot referme trois défauts de permission qui partagent une origine commune : le contrôle existe sur certains chemins vers un objet, et pas sur d’autres.
- Le jeton à portée réduite. Forgejo permet à un mainteneur d’éditer des branches qu’il ne possède pas quand une pull request ouverte porte l’option « permettre l’édition par le mainteneur ». Cette exception a été écrite contre un humain connecté, avant l’arrivée des jetons d’API à portée de dépôt. Le jeton que vous aviez délibérément restreint pouvait donc contourner la restriction.
- La release en brouillon. Les releases en brouillon sont censées être invisibles sans accès en écriture.
GetReleaseetListReleaseAttachmentsvérifiaient l’état brouillon avant de répondre ;GetReleaseAttachmentet la route web de téléchargement ne le faisaient pas. Un lecteur — y compris anonyme sur un dépôt public — pouvait récupérer le contenu complet d’une pièce jointe qui n’aurait jamais dû être visible. Forgejo signale qu’il s’agit de la même classe corrigée par Gitea en amont dans GHSA-q9pg-jj6x-j9p6, un avis de juillet, corrigé dans Gitea 1.27.0. - L’équipe admin. Classée en simple correction de bug plutôt qu’en sécurité : une équipe d’organisation définie sur
adminrecevait en réalité la permissionownersur ses dépôts liés. Sur une installation classique, c’est probablement l’élément le plus lourd du lot — il n’est pas dans la section sécurité uniquement parce que personne ne l’a signalé comme une vulnérabilité.
Le point commun : chaque fois, le contrôle avait été écrit correctement, mais ne siégeait pas sur le chemin qu’un attaquant emprunterait.
Votre scanner ne vous dira rien de tout ça
La partie la plus inconfortable est ailleurs. Une requête sur OSV, la base que consultent la plupart des scanners, renvoie 193 avis sous le chemin de module code.gitea.io/gitea, et zéro sous forgejo.org, le chemin que Forgejo publie réellement.
Ce n’est pas une affirmation que Forgejo est plus sûr que Gitea : c’est l’absence de toute affirmation, faute de données. Forgejo publie ses correctifs en prose dans ses notes de version sur Codeberg, souvent sans CVE du tout. Votre scanner de dépendances lit vos fichiers de verrouillage — et votre forge n’est dans aucun fichier de verrouillage. C’est une image de conteneur ou un binaire sur une VM, et rien dans votre pipeline ne compare sa version à un flux qui déclencherait une alerte.
Cela se généralise bien au-delà de ce projet. Les composants que l’analyse automatisée couvre sont ceux déclarés dans un manifeste. Tout ce qui est installé comme infrastructure en sort : la forge, le runner CI, le registre d’artefacts, le fournisseur d’identité. Ce sont précisément les composants dont la compromission n’est pas un incident de disponibilité mais un événement de chaîne d’approvisionnement — chaque artefact produit ensuite reste de confiance en aval, jusqu’à preuve du contraire.
Ce qu’il faut faire cette semaine
- Corriger vers 16.0.4 ou 15.0.8. Les deux branches portent les correctifs. Tout ce qui est en 16.0.3 ou avant est affecté : la fenêtre d’exposition est la durée de vie de votre instance, pas les quatre semaines écoulées depuis la dernière version.
- Établir qui peut publier un dépôt modèle sur votre instance. Si la création de modèles est ouverte à tous, ou si l’instance est publique ou multi-locataire, c’est un chemin d’entrée non fiable. Inspectez les processus hôtes et les répertoires de hooks, pas seulement les journaux d’accès.
- Inventorier vos jetons à granularité fine. Pour chacun, demandez si la restriction configurée est appliquée sur toutes les routes qui atteignent la ressource, ou seulement sur celle que vous avez testée à la création.
- Inscrire chaque service auto-hébergé hors manifeste sur une liste nominative avec un propriétaire nommé et un abonnement à son flux de versions — forge, runner, registre, fournisseur d’identité, gestionnaire de secrets.
Une forge souveraine, mais un angle mort identique
Rappel utile : Forgejo est le fork communautaire de Gitea, né fin 2022 après la tentative de privatisation de Gitea par une entreprise, et gouverné sous Codeberg. Beaucoup d’équipes européennes l’auto-hébergent précisément pour garder leur code hors de l’infrastructure américaine — ce qui rend l’angle mort de l’outillage d’autant plus ironique.
Une forge Forgejo auto-hébergée est par définition un actif de souveraineté : elle contient tout votre code source, vos secrets de déploiement et votre historique. Pourtant, parce qu’elle n’est dans aucun manifeste, elle échappe aux scanners qui surveillent vos dépendances. Le RCE du 10 septembre ne fait que rendre concret un risque que beaucoup d’équipes n’avaient jamais cartographié : la forge est la pièce la plus précieuse et la moins surveillée de leur infrastructure.
La parade n’est pas technique, elle est organisationnelle : un propriétaire nommé par service auto-hébergé, un abonnement à son flux de versions, et une revue régulière. Le reste — les correctifs, les audits par objet — découle de là.
Verdict
Forgejo 16.0.4 est une correction obligatoire et immédiate pour toute forge auto-hébergée, mais le patch n’est que la moitié du travail. La faille la plus grave n’est pas le RCE — c’est l’angle mort de l’outillage : votre forge n’est dans aucun manifeste, donc aucun scanner ne la surveille.
Si vous auto-hébergez Forgejo, passez en 16.0.4 ou 15.0.8 dès maintenant, puis vérifiez qui peut créer des dépôts modèles et auditez vos jetons à granularité fine sur toutes leurs routes.
Si vous gérez d’autres services auto-hébergés hors lockfile — Gitea, GitLab, un registre, un runner — appliquez la même règle : une liste nominative avec un propriétaire, et un abonnement au flux de versions. Le trou que personne ne lit, c’est le trou qu’un attaquant trouvera.