CVE-2026-46716 Security Alert: CRITICAL Vulnerability

Urgent: CVE-2026-46716 requires immediate attention.

· 7 min read

Executive Summary

CVE-2026-46716 is a critical authorization flaw in github.com/nezhahq/nezha that can let an authenticated RoleMember user trigger commands across all monitored servers. The issue affects the dashboard’s cron task routes, which are exposed to any logged-in user instead of admins only. A member can create a cron job with an empty server list and a “cover all” setting, bypassing permission checks and causing the dashboard to fan out attacker-controlled commands to every connected agent.

Impact: cross-tenant remote code execution, data exposure through task output, and potential full compromise of every host monitored by the deployment.

Immediate Action

  • Restrict access now: if possible, disable cron task creation and manual cron triggering at the dashboard layer until patched.
  • Upgrade immediately: move to a version that includes the vendor fix for CVE-2026-46716. Vendor advisory / security advisory.
  • Revoke suspicious member accounts: review all RoleMember users, especially OAuth2 self-bound accounts, and disable any untrusted access.
  • Rotate secrets: assume command output may have been exfiltrated via notification webhooks; rotate webhook URLs, API keys, cloud credentials, and any host secrets.
  • Isolate the dashboard and agents: temporarily segment the dashboard from production hosts if you cannot patch immediately.
  • Check cron jobs: look for recently created cron entries with empty server lists or broad coverage settings.

Affected Versions

  • github.com/nezhahq/nezha@<=50dc8e660326b9f22990898142c58b7a5312b42a vulnerable.
  • github.com/nezhahq/nezha@>=FIXED_COMMIT safe. TODO: replace FIXED_COMMIT with the upstream patched commit or release tag.
  • If you deploy from source, any build from master at or before the affected commit is at risk.

Resolution Guide

Go / source builds: update the module or pin to a fixed release.

go get github.com/nezhahq/nezha@FIXED_VERSION
go mod tidy
go build ./...

If you vendor the code: apply the authorization fix and redeploy.

// cmd/dashboard/controller/controller.go
auth.POST("/cron", adminHandler(createCron))
auth.PATCH("/cron/:id", adminHandler(updateCron))
auth.GET("/cron/:id/manual", adminHandler(manualTriggerCron))
auth.POST("/batch-delete/cron", adminHandler(batchDeleteCron))

Defense in depth: reject empty server lists for broad cron coverage and enforce per-server permission checks before dispatch.

if cf.Cover == model.CronCoverAll && len(cf.Servers) == 0 {
    return 0, errors.New("cover-all cron must list at least one ignored server")
}

Docker: rebuild with the patched source or move to a fixed image tag.

docker pull TODO-FIXED-IMAGE:TAG
docker stop nezha-dashboard
docker rm nezha-dashboard
docker run ... TODO-FIXED-IMAGE:TAG

Linux packages: if your environment uses a packaged build, upgrade via your package manager once the maintainer publishes a fixed package.

# apt
sudo apt update
sudo apt install --only-upgrade nezha-dashboard

# yum/dnf
sudo dnf upgrade nezha-dashboard

JavaScript/Python ecosystems: not directly applicable to the upstream Go project, but if your deployment wraps the dashboard in automation, update the pinned source revision in your build pipeline.

# Example CI pin
NEZHA_REF=FIXED_VERSION
git checkout "$NEZHA_REF"
go build ./...

Detection & Verification

Check your version or commit:

git rev-parse HEAD
git log -1 --oneline
go list -m all | grep nezhahq/nezha

Look for vulnerable cron behavior: search for cron routes using commonHandler instead of adminHandler, and for permission checks that accept empty server lists.

grep -R "POST /cron\|PATCH /cron\|commonHandler(createCron)\|commonHandler(updateCron)" -n cmd/dashboard
grep -R "CheckPermission" -n cmd/dashboard service | head

Inspect existing cron entries: flag jobs with Servers=[], broad coverage, or unknown notification groups.

# Example SQL if you have DB access
SELECT id, user_id, name, cover, servers, command, notification_group_id
FROM cron
WHERE servers = '[]' OR servers IS NULL;

Verify the fix: after patching, confirm that non-admin users receive HTTP 403/permission denied when attempting to create or edit cron jobs.

curl -i -X POST -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"test","task_type":0,"scheduler":"* * * * *","command":"id","servers":[],"cover":1}' \
  https://YOUR-DASHBOARD/api/v1/cron

Risk and Impact

This bug can turn a normal member account into a cross-tenant command execution path across every monitored host. Because the dashboard pushes cron output back through notification channels, attackers can also exfiltrate command results to a webhook they control. For small teams, the blast radius is especially severe: one low-privilege login can expose servers, credentials, and internal data across the whole deployment.

Keep reading