
PoC Python minimal pour CVE-2026-40179 : injecte un nom de métrique malveillant via le remote_write Prometheus non authentifié pour déclencher un XSS stocké dans l'interface web. Aucun stub protobuf requis.
remote_writeUne preuve de concept minimale et à dépendances légères pour CVE-2026-40179 (GHSA-vffh-x6r8-xx99) : cross-site scripting stocké dans l'interface web de Prometheus, délivré via un point de terminaison remote_write non authentifié.
Prometheus 3.x restitue les noms de métriques et les valeurs de labels dans l'interface web via innerHTML sans échappement. Comme Prometheus v3 a assoupli la validation des labels pour autoriser l'UTF-8 arbitraire — y compris <, >, et " — un nom de métrique peut transporter une charge utile HTML qui s'exécute lorsque quelqu'un consulte l'interface.
| Versions concernées | Prometheus 3.0.0 – 3.5.1 |
| Corrigé dans | 3.5.2 |
| Impact | XSS stocké, s'exécute dans le navigateur de tout utilisateur consultant la métrique concernée |
| Surfaces vulnérables | Infobulles de la page Graph, Metrics Explorer |
Le XSS lui-même nécessite un moyen d'introduire une série façonnée dans la TSDB. N'importe laquelle de ces options fonctionne :
remote_write ouvert (ce que ce PoC utilise),Un Prometheus exposé sur Internet ou sur un réseau local, sans authentification devant lui, offre tout ce qui précède gratuitement, ce qui rend cette vulnérabilité pratiquement exploitable plutôt que théorique.
Envoie un unique POST /api/v1/write contenant une série temporelle dont __name__ est :
pentest_poc_cve_2026_40179
Le WriteRequest protobuf est encodé à la main en ~40 lignes, donc il n'y a aucune dépendance à protobuf, prometheus_pb2 ou promtool — seulement python-snappy pour la compression sur le fil et requests pour le POST. Cela permet de le déposer facilement sur un hôte de rebond où l'on ne peut pas compiler de stubs protobuf générés.
python3 -m pip install python-snappy requests
python-snappy nécessite la bibliothèque C Snappy :
# Debian/Ubuntu
sudo apt install libsnappy-dev
# macOS
brew install snappy
python3 cve-2026-40179-poc.py <target_ip>
Le script suppose HTTPS sur le port 9090 avec la vérification du certificat désactivée (typique pour une instance interne avec un certificat auto-signé). Si votre cible est en HTTP simple ou sur un autre port, modifiez la ligne url dans main().
Une injection réussie renvoie HTTP 204 :
POST https://192.0.2.10:9090/api/v1/write -> 204
Interrogez la série dans l'interface Prometheus ou l'API — elle devrait être retournée immédiatement :
{__name__=~"pentest_poc.*"}
La vue Table l'échappe correctement et affiche la charge utile en texte brut. C'est attendu et cela ne constitue pas la surface vulnérable.
Ouvrez le Metrics Explorer (le navigateur de métriques à côté de la zone de requête), recherchez pentest_poc, puis survolez l'entrée listée.
Lors de tests sur le terrain contre 3.2.1, le chemin du Metrics Explorer s'est déclenché de manière fiable tandis que l'infobulle de l'onglet Graph ne s'est pas reproduite — l'échantillon injecté (valeur 1.0) n'était pas visiblement rendu sur le graphique tracé, et le survol de la légende ne l'a pas déclenché non plus. Les deux surfaces sont mentionnées dans l'avis ; si l'une ne se déclenche pas sur votre version cible, essayez l'autre avant de conclure que la vulnérabilité est absente.
La charge utile par défaut utilise console.log() afin de ne pas interrompre ceux qui ne la cherchent pas. Pour une démonstration visible — une capture d'écran pour un rapport, par exemple — modifiez METRIC_NAME pour utiliser alert() :
METRIC_NAME = ('pentest_poc_cve_2026_40179'
'')
La série injectée est persistante. Une fois écrite, elle reste dans la TSDB jusqu'à ce que la rétention l'expire. La supprimer nécessite l'API d'administration, qui est désactivée par défaut :
# Only works if Prometheus was started with --web.enable-admin-api
curl -X POST -g 'https://<target>:9090/api/v1/admin/tsdb/delete_series?match[]={__name__=~"pentest_poc.*"}'
curl -X POST 'https://<target>:9090/api/v1/admin/tsdb/clean_tombstones'
Si l'API d'administration est désactivée, il n'existe aucune voie de nettoyage à distance. La seule alternative est promtool tsdb exécuté localement sur l'hôte, auquel vous n'avez probablement pas accès.
Conséquences pratiques :
job="pentest_poc") afin d'être facile à trouver et clairement un artefact de test.Pour reproduire contre une instance jetable plutôt que contre un système en production :
docker run --rm -p 9090:9090 prom/prometheus:v3.2.1 \
--config.file=/etc/prometheus/prometheus.yml \
--web.enable-remote-write-receiver \
--web.enable-admin-api
Pointez ensuite le script vers 127.0.0.1 (changez le schéma d'URL en http:// dans main()). Démarrer avec --web.enable-admin-api signifie que vous pouvez réellement supprimer la série ensuite.
--web.config.file avec basic_auth_users.--web.enable-remote-write-receiver sauf si nécessaire, et ne l'exposez jamais sans authentification.Notez que (1) à lui seul corrige le XSS, mais un Prometheus non authentifié reste en soi une surface substantielle de divulgation d'informations : la liste complète des noms de métriques, l'inventaire des cibles de scrape et les noms d'hôtes internes sont tous lisibles sans identifiants.
Ceci est publié pour les défenseurs, chercheurs et testeurs travaillant sous autorisation. La vulnérabilité est publiquement divulguée et corrigée en amont.
Exécuter ceci contre un système y écrit des données persistantes. Ne le pointez pas vers une infrastructure que vous ne possédez pas ou pour laquelle vous n'avez pas d'autorisation écrite explicite de tester.
MIT — voir LICENSE.