Contexte technique
SourceHut repose sur plusieurs micro‑services, dont builds.sr.ht qui génère les journaux de compilation. Ces journaux sont convertis du texte brut contenant des séquences d’échappement ANSI en HTML grâce au script ansi2html.py. En septembre 2026, la découverte d’une vulnérabilité classée CVE‑2026‑92973 a montré que le convertisseur ne désinfectait pas correctement les séquences OSC 8, utilisées pour créer des hyperliens dynamiques.
Mécanisme de l’exploitation
L’attaquant injecte une chaîne contenant \33]8;; suivie d’une URL ou d’un protocole javascript:. Le convertisseur transforme cette séquence en un élément <a> avec des attributs tels que autofocus, tabindex ou onfocus. Le code suivant illustre le payload :
printf '\33]8;;https://example.com/\"/autofocus/tabindex=\"1\"/onfocus=\"alert`xss`\"\7Nothing to see here\33]8;;\7' | ansi2html [...]Le résultat HTML contient <a href="https://example.com/" autofocus tabindex="1" onfocus="alert`xss`">Nothing to see here</a>. Toute personne affichant le journal dans un navigateur exécute alors le script injecté.
Impact et portée
La vulnérabilité est qualifiée de « wormable » : un attaquant peut publier le texte malveillant via un patch public sur une liste de diffusion, déclenchant ainsi la création d’un job de build visible par tous les utilisateurs. Aucun compte n’est requis pour déposer le texte, ce qui rend l’exploitation triviale. Une fois le script exécuté, l’attaquant peut lire le jeton CSRF présent dans la page et soumettre des requêtes authentifiées, voire obtenir les clés de déploiement stockées sur le service.
Mitigations et limites
Le correctif consiste à renforcer la politique de sécurité du contenu (CSP) en supprimant unsafe‑inline et à ajouter une désinfection stricte des séquences OSC 8 avant la conversion. Le projet a déjà introduit une étape de nettoyage, mais celle‑ci a supprimé les couleurs, montrant le compromis entre fonctionnalité et sécurité. Une refonte du convertisseur en automate d’état pourrait éliminer les chemins d’injection. Tant que la CSP reste permissive et que le code de désinfection n’est pas complet, le vecteur reste exploitable sur toute instance utilisant le même script.