Environnement de laboratoire reproductible pour CVE-2026-46716, une RCE critique inter-locataire dans Nezha Monitoring via un contournement d'autorisation de l'API cron. Inclut un modèle de détection Nuclei et des clusters vulnérables/corrigés basés sur Docker.
Un environnement de laboratoire pour reproduire et détecter CVE-2026-46716, une vulnérabilité critique dans Nezha Monitoring où le point d'accès POST /api/v1/cron manque de vérifications de privilèges administrateur, permettant aux utilisateurs RoleMember de réaliser une exécution de code à distance inter-locataire.
| Champ | Détails |
|---|---|
| ID CVE | CVE-2026-46716 |
| GHSA | GHSA-99gv-2m7h-3hh9 |
| CVSS | 9.9 (Critique) — AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H |
| Versions affectées | nezhahq/nezha >= 1.4.0, < 1.14.15-0.20260517022419-d7526351cf97 |
| Corrigée | v1.14.15-0.20260517022419-d7526351cf97 (commit d7526351cf97, 2026-05-17) |
| CWE | CWE-862 (Autorisation manquante), CWE-269 (Gestion de privilèges inappropriée), CWE-78 (Injection de commande OS) |
Chemin vulnérable :
POST /api/v1/cron → commonHandler (authentification JWT uniquement, pas de vérification de rôle)
→ CheckPermission(servers=[])
→ itère une liste vide → retourne true sans condition
→ CronTrigger envoie la commande à TOUS les serveurs via la map ServerShared
❌ Pas de vérification admin, pas de validation de propriété → RCE inter-locataire
Chemin corrigé :
POST /api/v1/cron → commonHandler (identique — HTTP 200 toujours renvoyé pour les membres)
→ CheckPermission(servers=[]) → true (inchangé)
→ CronTrigger : cronCanSendToServer(cr, s) vérifie cr.UserID == s.UserID
✅ Commandes envoyées uniquement aux serveurs appartenant au créateur de la tâche cron
| # | Condition | Détails |
|---|---|---|
| 1 | Version Nezha affectée | < 1.14.15-0.20260517022419 |
| 2 | Compte authentifié | RoleMember (niveau de privilège le plus bas) |
| 3 | Liste de serveurs vide | "servers":[], "cover":1 contourne CheckPermission |
Machine hôte
├── localhost:8008 ──→ Docker: nezha-vuln (v1.14.14 ⚠ VULNÉRABLE)
└── localhost:8009 ──→ Docker: nezha-patched (commit d7526351cf97 ✓ CORRIGÉ, compilé à partir des sources)
| Outil | Installation |
|---|---|
| Docker Desktop | docker.com |
| nuclei | brew install nuclei |
| curl, python3 | préinstallés sur macOS |
bash scripts/01-setup.sh
Une fois terminé :
══════════════════════════════════════════════════════
Laboratoire prêt !
══════════════════════════════════════════════════════
Vulnérable (v1.14.14) : http://localhost:8008
Corrigé (dernière version) : http://localhost:8009
Administrateur : admin / admin
Membre : member / Memberpass123!
══════════════════════════════════════════════════════
Remarque : si l'API de création de compte membre diffère de celle attendue, créez-le manuellement via l'interface Nezha à l'adresse
http://localhost:8008(Paramètres → Utilisateurs).
bash scripts/03-trigger-cve.sh
Résultat attendu — vulnérable (v1.14.14) :
HTTP 200 — Cron créée (id : 1)
⚠ RÉSULTAT : CONTRÔLE ADMINISTRATEUR CONTOURNÉ — VULNÉRABLE
Résultat attendu — corrigé :
HTTP 403 — Accès refusé
✓ RÉSULTAT : Contrôle administrateur appliqué — CORRIGÉ
# Cluster vulnérable → devrait produire un résultat [critique]
nuclei -duc -t nuclei/CVE-2026-46716.yaml \
-u http://localhost:8008 \
-var username=admin \
-var password=admin
# Cluster corrigé → ne devrait produire aucun résultat
nuclei -duc -t nuclei/CVE-2026-46716.yaml \
-u http://localhost:8009 \
-var username=admin \
-var password=admin
bash scripts/99-teardown.sh
nezha-cve-2026-46716-lab/
├── README.md
├── LAB_SETUP_GUIDE.md # Guide de configuration du laboratoire (anglais)
├── VULNERABILITY_ANALYSIS.md # Analyse de la vulnérabilité au niveau du code (anglais)
├── NUCLEI_TEMPLATE_GUIDE.md # Conception du modèle Nuclei et résultats de test (anglais)
├── docker-compose.yaml
│
├── REPORT/ # Rapports en coréen
│ ├── LAB_REPORT_KR.md
│ ├── Nuclei_Template_Report_KR.md
│ └── Vulnerability_Analysis_KR.md
│
├── nuclei/
│ └── CVE-2026-46716.yaml # Modèle de détection Nuclei
│
└── scripts/
├── 01-setup.sh # Lancer les conteneurs, créer le compte membre
├── 03-trigger-cve.sh # Preuve de concept : déclencher le contournement d'authentification, vérifier le résultat
└── 99-teardown.sh # Arrêter et supprimer toutes les ressources du laboratoire
Étape 1 POST /api/v1/login (identifiants administrateur)
→ s'authentifier et extraire le jeton JWT
Étape 2 GET /api/v1/setting
→ le champ version est comparé à la plage vulnérable (1.4.x – 1.14.14)
→ correspondance → RÉSULTAT : version vulnérable détectée
→ pas de correspondance (>= 1.14.15 ou "debug") → aucun résultat
Les versions vulnérable et corrigée renvoient toutes deux HTTP 200 pour POST /api/v1/cron avec servers:[], cover:1 — la détection comportementale n'est pas possible. Le correctif ajoute uniquement une validation de propriété à l'intérieur de CronTrigger au moment de l'exécution, pas au niveau de l'API. Les identifiants administrateur sont requis car GET /api/v1/setting ne renvoie le champ version que pour les utilisateurs RoleAdmin.
Avertissement : tous les identifiants de ce laboratoire sont des données de test factices utilisées uniquement à des fins de recherche en sécurité. Ne jamais les utiliser en production.