# CVE-2026-46716 Nuclei Detection Template Guide --- ## 1. Overview This document describes the design and test results of the nuclei template for CVE-2026-46716 (Nezha Monitoring CronTrigger delivery authorization bypass → Cross-Tenant RCE). **Key discovery**: both vulnerable and patched versions return HTTP 200 for `POST /api/v1/cron` with `servers:[], cover:1` from a member account — the API acceptance behavior is identical. The patch only adds ownership validation inside CronTrigger at execution time. Therefore, version-based detection via `GET /api/v1/setting` is used as the distinguishing signal. --- ## 2. Detection Approach | Item | Details | |------|---------| | Detection type | **Version-based** — compares installed version against vulnerable range | | Required credentials | Admin (version field in `/api/v1/setting` is admin-only) | | Vulnerable indicator | `"version"` matches 1.4.x – 1.14.14 | | Patched indicator | `"version"` is >= 1.14.15 or absent (e.g., `"debug"` for source builds) | | Why not behavior-based | Both versions return HTTP 200 for member cron creation; actual execution difference requires connected agents | --- ## 3. Template Architecture ``` Step 1 POST /api/v1/login (admin credentials) → Authenticate and extract JWT token → Internal matcher: body contains "data" and "token" → If match fails, step 2 is skipped (flow: http(1) && http(2)) Step 2 GET /api/v1/setting → Extract "version" field (only returned for admin-role users) → Regex match against vulnerable version range: 1.4.x – 1.14.14 → Match → FINDING reported → No version match (>= 1.14.15 or "debug") → no finding ``` ### Version Range Regex ```yaml regex: - '"version":"1\.[4-9]\.[0-9]+"' # 1.4.x – 1.9.x - '"version":"1\.1[0-3]\.[0-9]+"' # 1.10.x – 1.13.x - '"version":"1\.14\.([0-9]|1[0-4])"' # 1.14.0 – 1.14.14 ``` --- ## 4. Usage ```bash # Scan vulnerable instance (admin credentials required) nuclei -duc -u http://localhost:8008 \ -t nuclei/CVE-2026-46716.yaml \ -var username=admin -var password=admin # Scan patched instance (should show 0 findings) nuclei -duc -u http://localhost:8009 \ -t nuclei/CVE-2026-46716.yaml \ -var username=admin -var password=admin ``` --- ## 5. Test Results ### Template Validation ``` nuclei -duc -validate -t nuclei/CVE-2026-46716.yaml [INF] All templates validated successfully ``` ### True-Positive (vulnerable v1.14.14) ``` nuclei -duc -u http://127.0.0.1:8008 \ -t nuclei/CVE-2026-46716.yaml \ -var username=admin -var password=admin [CVE-2026-46716] [http] [critical] http://127.0.0.1:8008 [INF] Scan completed ... 1 matches found. ``` GET /api/v1/setting returns `"version":"1.14.14"` — matches the vulnerable range regex. ### False-Positive Validation (patched source build) ``` nuclei -duc -u http://127.0.0.1:8009 \ -t nuclei/CVE-2026-46716.yaml \ -var username=admin -var password=admin [INF] Scan completed ... 0 matches found. ``` GET /api/v1/setting returns `"version":"debug"` for source builds — does not match the version regex, so no finding is produced. Production patched deployments (>= v1.14.15) also produce no finding. --- ## 6. Vulnerability Background The vulnerability has two components: **Component 1 — CheckPermission accepts empty server list without validation (present in both versions):** `CheckPermission` iterates the provided server ID list to verify ownership. When `servers:[]` is passed, the loop body never executes — no ownership check occurs and the function returns `true`, allowing any authenticated user to create a cron with `cover:1` (all servers). **Component 2 — CronTrigger delivery bypass (fixed in patch):** Before patch: `CronTrigger` iterates all connected agents in `ServerShared` without verifying that each agent belongs to the cron creator. With `cover:1`, every connected agent receives the command — cross-tenant RCE. After patch: `cronCanSendToServer()` checks `cr.UserID == server.UserID || userIsAdmin(cr.UserID)` before each dispatch, restricting delivery to owned servers. --- ## 7. Important Notes - Admin credentials are required for detection because `"version"` in `GET /api/v1/setting` is only returned for RoleAdmin users. - The template does not create any cron jobs — it is read-only (login + version check). - Always obtain proper authorization before scanning production systems. ---