
CVE-2026-46716에 대한 재현 가능한 실험 환경입니다. 이는 크론 API 인증 우회를 통한 Nezha Monitoring의 심각한 교차 테넌트 RCE 취약점입니다. Nuclei 탐지 템플릿과 Docker 기반의 취약한/패치된 클러스터를 포함합니다.
| 항목 | 세부 정보 |
|---|
| CVE ID | CVE-2026-46716 |
| GHSA | GHSA-99gv-2m7h-3hh9 |
| CVSS | 9.9 (Critical) — AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H |
| 영향 받는 버전 | nezhahq/nezha >= 1.4.0, < 1.14.15-0.20260517022419-d7526351cf97 |
| 패치 버전 | v1.14.15-0.20260517022419-d7526351cf97 (커밋 d7526351cf97, 2026-05-17) |
| CWE | CWE-862 (인증 누락), CWE-269 (부적절한 권한 관리), CWE-78 (OS 명령 삽입) |
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
| # | 조건 | 세부 사항 |
|---|---|---|
| 1 | 영향 받는 Nezha 버전 | < 1.14.15-0.20260517022419 |
| 2 | 인증된 계정 | RoleMember (최소 권한 수준) |
| 3 | 빈 서버 목록 | "servers":[], "cover":1가 CheckPermission을 우회합니다 |
호스트 머신
├── localhost:8008 ──→ Docker: nezha-vuln (v1.14.14 ⚠ 취약)
└── localhost:8009 ──→ Docker: nezha-patched (커밋 d7526351cf97 ✓ 패치됨, 소스에서 빌드)
| 도구 | 설치 방법 |
|---|---|
| Docker Desktop | docker.com |
| nuclei | brew install nuclei |
| curl, python3 | macOS에 사전 설치됨 |
bash scripts/01-setup.sh
완료되면:
══════════════════════════════════════════════════════
Lab ready!
══════════════════════════════════════════════════════
Vulnerable (v1.14.14) : http://localhost:8008
Patched (latest) : http://localhost:8009
Admin : admin / admin
Member : member / Memberpass123!
══════════════════════════════════════════════════════
참고: 멤버 계정 생성 API가 예상과 다른 경우, Nezha UI (http://localhost:8008)에서 수동으로 생성하세요. (설정 → 사용자)
bash scripts/03-trigger-cve.sh
예상 출력 — 취약 (v1.14.14):
HTTP 200 — Cron created (id: 1)
⚠ RESULT: ADMIN CHECK BYPASSED — VULNERABLE
예상 출력 — 패치됨:
HTTP 403 — Access denied
✓ RESULT: Admin check enforced — PATCHED
# 취약 클러스터 → [critical] 결과가 나와야 함
nuclei -duc -t nuclei/CVE-2026-46716.yaml \
-u http://localhost:8008 \
-var username=admin \
-var password=admin
# 패치 클러스터 → 결과가 없어야 함
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 # 실습 설정 가이드 (영어)
├── VULNERABILITY_ANALYSIS.md # 코드 수준 취약점 분석 (영어)
├── NUCLEI_TEMPLATE_GUIDE.md # Nuclei 템플릿 설계 및 테스트 결과 (영어)
├── docker-compose.yaml
│
├── REPORT/ # 한국어 보고서
│ ├── LAB_REPORT_KR.md
│ ├── Nuclei_Template_Report_KR.md
│ └── Vulnerability_Analysis_KR.md
│
├── nuclei/
│ └── CVE-2026-46716.yaml # Nuclei 탐지 템플릿
│
└── scripts/
├── 01-setup.sh # 컨테이너 시작, 멤버 계정 생성
├── 03-trigger-cve.sh # PoC: 인증 우회 트리거, 결과 확인
└── 99-teardown.sh # 모든 실습 리소스 중지 및 제거
Step 1 POST /api/v1/login (admin credentials)
→ authenticate and extract JWT token
Step 2 GET /api/v1/setting
→ version field matched against vulnerable range (1.4.x – 1.14.14)
→ match → FINDING: vulnerable version detected
→ no match (>= 1.14.15 or "debug") → no finding
취약 버전과 패치 버전 모두 POST /api/v1/cron에 대해 servers:[], cover:1과 함께 HTTP 200을 반환하므로 행동 기반 탐지는 불가능합니다. 패치는 API 수준이 아니라 CronTrigger 내 실행 시점에 소유권 검증만 추가합니다. Admin 자격 증명이 필요한 이유는 GET /api/v1/setting이 version 필드를 RoleAdmin 사용자에게만 반환하기 때문입니다.
경고: 이 실습의 모든 자격 증명은 보안 연구 목적의 가짜 테스트 데이터입니다. 절대 프로덕션에서 사용하지 마세요.