
Ambiente de laboratório reproduzível para CVE-2026-46716, uma RCE crítica entre inquilinos no Nezha Monitoring por meio de bypass de autorização da API cron. Inclui template de detecção Nuclei e clusters vulneráveis/corrigidos baseados em Docker.
Um ambiente de laboratório para reproduzir e detectar CVE-2026-46716, uma vulnerabilidade crítica no Nezha Monitoring onde o endpoint POST /api/v1/cron carece de verificações de privilégio de administrador, permitindo que usuários RoleMember obtenham execução remota de código entre tenants.
| Campo | Detalhes |
|---|---|
| CVE ID | CVE-2026-46716 |
| GHSA | GHSA-99gv-2m7h-3hh9 |
| CVSS | 9.9 (Crítica) — AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H |
| Versões afetadas | nezhahq/nezha >= 1.4.0, < 1.14.15-0.20260517022419-d7526351cf97 |
| Corrigida | v1.14.15-0.20260517022419-d7526351cf97 (commit d7526351cf97, 2026-05-17) |
| CWE | CWE-862 (Falta de Autorização), CWE-269 (Gerenciamento de Privilégios Improprio), CWE-78 (Injeção de Comandos do SO) |
Vulnerable path:
POST /api/v1/cron → commonHandler (JWT auth only, no role check)
→ CheckPermission(servers=[])
→ iterates empty list → returns true unconditionally
→ CronTrigger dispatches command to ALL servers via ServerShared map
❌ No admin check, no ownership validation → cross-tenant RCE
Patched path:
POST /api/v1/cron → commonHandler (same — HTTP 200 still returned for members)
→ CheckPermission(servers=[]) → true (unchanged)
→ CronTrigger: cronCanSendToServer(cr, s) checks cr.UserID == s.UserID
✅ Commands only dispatched to servers owned by the cron creator
| # | Condição | Detalhes |
|---|---|---|
| 1 | Versão afetada do Nezha |
Host Machine
├── localhost:8008 ──→ Docker: nezha-vuln (v1.14.14 ⚠ VULNERABLE)
└── localhost:8009 ──→ Docker: nezha-patched (commit d7526351cf97 ✓ PATCHED, built from source)
| Ferramenta | Instalação |
|---|---|
| Docker Desktop | docker.com |
| nuclei | brew install nuclei |
| curl, python3 | pré-instalado no macOS |
bash scripts/01-setup.sh
Quando finalizado:
══════════════════════════════════════════════════════
Lab ready!
══════════════════════════════════════════════════════
Vulnerable (v1.14.14) : http://localhost:8008
Patched (latest) : http://localhost:8009
Admin : admin / admin
Member : member / Memberpass123!
══════════════════════════════════════════════════════
Nota: Se a API de criação de conta de membro diferir do esperado, crie-a manualmente através da interface do Nezha em
http://localhost:8008(Configurações → Usuários).
bash scripts/03-trigger-cve.sh
Saída esperada — vulnerável (v1.14.14):
HTTP 200 — Cron created (id: 1)
⚠ RESULT: ADMIN CHECK BYPASSED — VULNERABLE
Saída esperada — corrigida:
HTTP 403 — Access denied
✓ RESULT: Admin check enforced — PATCHED
# Cluster vulnerável → deve produzir um achado [critical]
nuclei -duc -t nuclei/CVE-2026-46716.yaml \
-u http://localhost:8008 \
-var username=admin \
-var password=admin
# Cluster corrigido → não deve produzir achados
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 # Lab setup guide (English)
├── VULNERABILITY_ANALYSIS.md # Code-level vulnerability analysis (English)
├── NUCLEI_TEMPLATE_GUIDE.md # Nuclei template design and test results (English)
├── docker-compose.yaml
│
├── REPORT/ # Korean reports
│ ├── LAB_REPORT_KR.md
│ ├── Nuclei_Template_Report_KR.md
│ └── Vulnerability_Analysis_KR.md
│
├── nuclei/
│ └── CVE-2026-46716.yaml # Nuclei detection template
│
└── scripts/
├── 01-setup.sh # Start containers, create member account
├── 03-trigger-cve.sh # PoC: trigger auth bypass, verify result
└── 99-teardown.sh # Stop and remove all lab resources
Passo 1 POST /api/v1/login (credenciais admin)
→ autenticar e extrair token JWT
Passo 2 GET /api/v1/setting
→ campo version comparado com a faixa vulnerável (1.4.x – 1.14.14)
→ correspondência → ACHADO: versão vulnerável detectada
→ sem correspondência (>= 1.14.15 ou "debug") → nenhum achado
Tanto a versão vulnerável quanto a corrigida retornam HTTP 200 para POST /api/v1/cron com servers:[], cover:1 — a detecção comportamental não é possível. A correção adiciona apenas validação de propriedade dentro do CronTrigger no momento da execução, não no nível da API. Credenciais de administrador são necessárias porque GET /api/v1/setting retorna o campo version apenas para usuários RoleAdmin.
Aviso: Todas as credenciais neste laboratório são dados de teste falsos para fins de pesquisa de segurança. Nunca use em produção.
| < 1.14.15-0.20260517022419 |
| 2 | Conta autenticada | RoleMember (menor nível de privilégio) |
| 3 | Lista vazia de servidores | "servers":[], "cover":1 ignora CheckPermission |