Skip to content

← Public intelligence

Go package

github.com/nezhahq/nezha

Open actionable advisories and recorded vendor fixes. This public package view has no inventory attached and cannot establish whether your deployment is affected. A vendor fix never resolves your finding; verify your installed version and the source guidance.

Open advisories

14 actionable advisories, newest first. Withdrawn advisories and news are excluded. Coverage is partial.

  1. Medium, CVSS 6.5GoAmendedPublished

    Nezha Monitoring: Whole-instance DoS in Nezha dashboard: a member can crash the process for every tenant

    CVE-2026-100394 · GHSA-qjpp-gffx-2wm9

    Affected
    • Go github.com/nezhahq/nezha >= 0.0.0-20260628010923-fd31e5f1b0f8, < 0.0.0-20260721131105-c893aa57867d
    Fixed in
    0.0.0-20260721131105-c893aa57867d· Vendor fix available
    Issue
    A single low-privilege RoleMember can take the entire Nezha dashboard offline, and with it every tenant's web UI, REST API, and agent connections, by racing two ordinary operations on their own service. The crash is a nil pointer dereference in the service-monitor worker at service/singleton/servicesentinel.go:601. The worker checks a service exists under one lock and later writes to two pointer-valued status maps under a different lock; a concurrent delete removes the entries in the gap. Because the gRPC server has no recovery interceptor, the worker-goroutine panic kills the whole process. Availability only: nothing is read or modified. Affected versions Confirmed in v2.2.7 through v2.2.10. service/singleton/servicesentinel.go has the same vulnerable implementation in all four releases. The issue is fixed in v2.2.11 and later; users should upgrade to the latest release, v2.3.0. The bug The worker validates an incoming report and later writes it to two status maps, but the…

    Recommended action: Upgrade to 0.0.0-20260721131105-c893aa57867d (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  2. Medium, CVSS 5.5GoPublished

    Nezha Dashboard: DDNS and Notification credential exposure via unredacted list API

    GHSA-ww5p-j6cj-6mqq

    Affected
    • Go github.com/nezhahq/nezha < 2.2.5
    Fixed in
    2.2.5· Vendor fix available
    Issue
    The GET /api/v1/ddns and GET /api/v1/notification endpoints return full resource objects including plaintext third-party API credentials — Cloudflare API tokens, TencentCloud SecretKeys, Slack/Discord/Telegram webhook URLs with embedded bot tokens, and Authorization header values — without any field-level redaction. Any authenticated admin who calls these endpoints receives every stored credential in the system in a single API response. A compromised admin session or leaked PAT with nezha:ddns:read or nezha:notification:read scope exposes all third-party integration secrets. Details The listDDNS and listNotification handlers follow an identical pattern: they call the corresponding singleton GetSortedList(), copier.Copy the full in-memory structs into a response slice, and return them via listHandler with zero field stripping. DDNS — cmd/dashboard/controller/ddns.go:25–33: The DDNSProfile struct (model/ddns.go:20–36) serializes AccessSecret with json:"accesssecret,omitempty" —…

    Recommended action: Upgrade to 2.2.5 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →
  3. Medium, CVSS 6.8GoPublished

    Nezha Monitoring: OAuth2 Redirect URL — Host Header Injection

    CVE-2026-53523 · GHSA-9rc6-8cjv-rcvx

    Affected
    • Go github.com/nezhahq/nezha >= 1.0.0, < 2.2.0
    Fixed in
    2.2.0· Vendor fix available
    Issue
    1. Description The getRedirectURL function in oauth2.go:22-29 constructs the OAuth2 callback URL by concatenating the request's Host header with a fixed path, with zero validation of the Host header: File: cmd/dashboard/controller/oauth2.go:22-29 This function is called from oauth2redirect() at line 53: The redirectURL is passed into o2confRaw.Setup(redirectURL) which configures the OAuth2 Config.RedirectURL field (oauth2config.go:22-33). This RedirectURL is sent to the OAuth2 provider (e.g., GitHub, Google, Microsoft) as the callback endpoint. The OAuth2 provider will redirect the user's browser — along with the authorization code — to this URL after the user authenticates. The security issue is that c.Request.Host is directly user-controllable via the HTTP Host header. An attacker who can control which Host header reaches the oauth2redirect handler can: 1. Set Host: evil.com 2. getRedirectURL returns https://evil.com/api/v1/oauth2/callback 3. The OAuth2 provider redirects the…

    Recommended action: Upgrade to 2.2.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →
  4. Medium, CVSS 6.5GoPublished

    Nezha Monitoring: Unbounded WebSocket Streams — Resource Exhaustion DoS

    CVE-2026-53522 · GHSA-jg62-j5h6-8mpq

    Affected
    • Go github.com/nezhahq/nezha >= 1.0.0, < 2.2.0
    Fixed in
    2.2.0· Vendor fix available
    Issue
    1. Description The Nezha dashboard exposes two endpoints that create long-lived WebSocket streams to monitored agents: - POST /api/v1/terminal → createTerminal() (terminal.go:27-67) - POST /api/v1/file → createFM() (fm.go:28-67) Both call rpc.NezhaHandlerSingleton.CreateStream(streamId, ...) which inserts a new ioStreamContext into an unbounded map[string]ioStreamContext (s.ioStreams in iostream.go:59-67). There is no per-user rate limit, no global semaphore, and no per-server connection cap. Each stream allocates: 1. A ioStreamContext struct with several channels and sync primitives 2. Two goroutines via StartStream() (iostream.go:358-369) — bidirectional io.CopyBuffer 3. A gRPC IOStream between the dashboard and the agent 4. An agent-side PTY/shell process Vulnerable code: terminal.go:27-67 — createTerminal: fm.go:28-67 — createFM: iostream.go:55-67 — CreateStreamWithPurpose (inserts into unbounded map): iostream.go:319-372 — StartStream spawns two goroutines per stream: The…

    Recommended action: Upgrade to 2.2.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →
  5. Critical, CVSS 9.1GoPublished

    Nezha Monitoring: Pre-auth path traversal via /dashboard.. prefix confusion leaks jwt_secret_key

    CVE-2026-53519 · GHSA-5c25-7vpj-9mqh

    Affected
    • Go github.com/nezhahq/nezha < 2.0.13
    Fixed in
    2.0.13· Vendor fix available
    Issue
    fallbackToFrontend in the dashboard's NoRoute handler treats any URL whose raw string starts with /dashboard as an admin-frontend asset request. The check uses strings.HasPrefix, not a path-segment match, so the input /dashboard../data/config.yaml is accepted; strings.TrimPrefix leaves ../data/config.yaml; and path.Join("admin-dist", "../data/config.yaml") normalizes to data/config.yaml — which os.Stat finds and http.ServeFile returns. No authentication required. In default deployments (the values shipped in model/config.go and the layout shipped in the project Dockerfile) data/config.yaml contains the HS256 jwtsecretkey used by cmd/dashboard/controller/jwt.go to sign every dashboard session cookie. A unauth attacker reads that secret, forges an admin JWT, and signs in as any user — full dashboard takeover from one GET request. Details Root cause fallbackToFrontend is wired as the catch-all at cmd/dashboard/controller/controller.go:157 —…

    Recommended action: Upgrade to 2.0.13 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →
  6. Medium, CVSS 6.4GoPublished

    Nezha Monitoring: Stored future DDNS profile ID allows unauthorized use of another user's DDNS profile context

    CVE-2026-53521 · GHSA-39g2-8x68-pmx8

    Affected
    • Go github.com/nezhahq/nezha >= 2.0.14, < 2.1.0
    Fixed in
    2.1.0· Vendor fix available
    Issue
    PATCH /server/{id} accepts and persists nonexistent ddnsprofiles IDs for a member-owned server. If another user later creates a DDNS profile with one of those IDs, the DDNS worker resolves the stored ID and dispatches an update using the other user's DDNS profile configuration in the context of the attacker's server. This is a second-order authorization bypass: direct binding to an existing foreign DDNS profile is correctly denied, but an unresolved future ID can be stored first and later becomes a live cross-user reference. Affected versions Confirmed on: - Nezha v2.0.14 - Commit: 8b5e382fe217107c7b777ea9c6b4bc3d2e156202 The exact affected version range was not determined. Impact A normal member who owns a server can prebind one or more future DDNS profile IDs to that server. If another user later creates a DDNS profile with a matching ID, the dashboard DDNS worker can use the victim's DDNS profile/provider configuration for the attacker's server. In the validated worker…

    Recommended action: Upgrade to 2.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →
  7. Medium, CVSS 6.5GoPublished

    Nezha Monitoring: Authenticated users can claim the dashboard Host through NAT and preempt all dashboard routing

    CVE-2026-53520 · GHSA-x6fg-52vr-hj4w

    Affected
    • Go github.com/nezhahq/nezha >= 2.0.14, < 2.1.0
    Fixed in
    2.1.0· Vendor fix available
    Issue
    An authenticated non-admin user who owns any server can create or update a NAT profile whose domain is equal to the dashboard's own HTTP Host (for example, dashboard.example:8008). The dashboard's top-level HTTP/gRPC multiplexer checks NATShared.GetNATConfigByDomain(r.Host) before dispatching requests to the dashboard API, frontend, or gRPC handler, so a member-controlled NAT profile for the dashboard Host takes precedence over the real dashboard. A disabled claimed NAT profile blocks matching dashboard requests before they reach the dashboard handler. An enabled claimed NAT profile routes matching requests into ServeNAT, which sends a NAT task to the member's selected agent and wraps the original HTTP request into the NAT IO stream. This allows a low-privileged dashboard user to take over routing for a global host name that should be reserved for the dashboard operator. Tested locally against commit 8b5e382fe217107c7b777ea9c6b4bc3d2e156202 of github.com/nezhahq/nezha.…

    Recommended action: Upgrade to 2.1.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →
  8. Critical, CVSS 9.9GoPublished

    Nezha vulnerable to cross-tenant terminal/file-manager session hijack via WebSocket stream UUID without ownership check

    GHSA-q6xx-5vr8-p898

    Affected
    • Go github.com/nezhahq/nezha >= 1.14.13, <= 1.14.14; >= 2.0.0, <= 2.0.9
    Fixed in
    2.0.10· Partial vendor fix
    Issue
    In nezha v1.14.13–v1.14.14 and v2.0.0–v2.0.9, the WebSocket endpoints GET /ws/terminal/:id and GET /ws/file/:id authenticate the caller only by the presence of a valid stream UUID, with no ownership check tying that UUID to the user who created the stream. Any authenticated dashboard user (including a RoleMember) who learns a live stream UUID can attach to the session and gain interactive shell access or full file-manager control on the target server — i.e. cross-tenant RCE. This was silently fixed in commit 6661d6a (2026-05-18, shipped in v2.0.10). At submission time no public CVE/GHSA covers this fix, so operators of v1.14.x and pre-v2.0.10 v2.x deployments have no signal that they are running vulnerable code. Details Stream allocation — service/rpc/iostream.go (v2.0.9): No creator is bound to the stream. Stream attach — cmd/dashboard/controller/terminal.go (v2.0.9): The only authorization check is GetStream(streamId) — "does this UUID exist in the in-memory map". getUid(c)…

    Recommended action: Upgrade to 2.0.10; some affected versions have no fix yet, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →
  9. Medium, CVSS 5.3GoPublished

    Nezha's private services (EnableShowInService: false) are enumerable via per-server endpoints, leaking name and timing data

    CVE-2026-49397 · GHSA-vrmh-5mmx-hjwx

    Affected
    • Go github.com/nezhahq/nezha >= 2.0.0, < 2.0.14
    Fixed in
    2.0.14· Vendor fix available
    Issue
    Private services (EnableShowInService: false) are enumerable via per-server endpoints, leaking name and timing data CWE: CWE-285 (Improper Authorization) via CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor) and CWE-863 (Incorrect Authorization — inconsistent gating across data-reader paths) CVSS v3.1: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N → 5.3 (Medium) Summary The EnableShowInService flag on a Service is meant to gate that service's visibility from the public dashboard. The main service-listing endpoint (GET /api/v1/service → showService) correctly filters services with EnableShowInService: false via ServiceSentinel.CopyStats() (service/singleton/servicesentinel.go:421-438). However, two adjacent reader endpoints retrieve service objects through code paths that do not honor the same flag: - GET /api/v1/server/:id/service (listServerServices) iterates ServiceSentinel.GetSortedList() (which returns every service regardless of visibility) and emits service…

    Recommended action: Upgrade to 2.0.14 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →
  10. High, CVSS 7.1GoPublished

    Nezha has cross-site GET request that can trigger stored cron commands on a victim's agents

    CVE-2026-49396 · GHSA-8qhj-4f8c-j8qg

    Affected
    • Go github.com/nezhahq/nezha >= 1.0.0, < 2.0.14
    Fixed in
    2.0.14· Vendor fix available
    Issue
    The dashboard exposes the cron manual-trigger action as an authenticated GET /api/v1/cron/:id/manual endpoint. Dashboard JWTs are sent in the nz-jwt cookie and configured with SameSite=Lax, which browsers include on top-level cross-site GET navigations. Because this state-changing GET endpoint has no CSRF token, origin validation, or fetch-metadata guard, an attacker can cause a logged-in Nezha user to trigger one of their existing cron tasks by navigating the victim's browser to the manual-trigger URL. If the targeted cron task sends a command to an online agent, the stored command is dispatched to the agent task stream. The attacker cannot create or modify the cron command through this issue alone, but can force execution of a command that the victim already saved and is authorized to run. Details Source-to-sink chain: 1. The dashboard registers the manual cron trigger as a GET route under the authenticated API group: auth.GET("/cron/:id/manual",…

    Recommended action: Upgrade to 2.0.14 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →
  11. Medium, CVSS 6.5GoPublished

    Nezha Monitoring: Nezha WebSocket server stream discloses cross-tenant server telemetry to authenticated members

    CVE-2026-47124 · GHSA-hvv7-hfrh-7gxj

    Affected
    • Go github.com/nezhahq/nezha >= 1.4.0, < 1.14.15-0.20260517034128-05e5da253519
    Fixed in
    1.14.15-0.20260517034128-05e5da253519· Vendor fix available
    Issue
    Any authenticated non-admin member can connect to the server-status WebSocket and receive telemetry for all servers, including servers owned by other users. The normal server list API filters objects by HasPermission, but the WebSocket stream treats the presence of any authenticated user as authorization for the full unfiltered server list. Details The server WebSocket route is registered under the optional-auth group in cmd/dashboard/controller/controller.go:71-73: serverStream treats any CtxKeyAuthorizedUser as a member, without checking admin role or per-server ownership, in cmd/dashboard/controller/ws.go:123-139: The authorization boolean is then used as a full/guest switch in getServerStat in cmd/dashboard/controller/ws.go:160-184: For authenticated members, GetSortedList() returns all servers and server.Host is not filtered. There is no call to server.HasPermission(c). The streamed response model in model/serverapi.go:5-20 includes server ID/name, public note, host…

    Recommended action: Upgrade to 1.14.15-0.20260517034128-05e5da253519 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →
  12. Critical, CVSS 9.9GoPublished

    Nezha Monitoring: RoleMember can run shell on every server (cross-tenant RCE) via POST /api/v1/cron

    CVE-2026-46716 · GHSA-99gv-2m7h-3hh9

    Affected
    • Go github.com/nezhahq/nezha >= 1.4.0, < 1.14.15-0.20260517022419-d7526351cf97
    Fixed in
    1.14.15-0.20260517022419-d7526351cf97· Vendor fix available
    Issue
    nezha's dashboard supports two user roles: RoleAdmin (Role==0) and RoleMember (Role==1). The cron routes POST /api/v1/cron and PATCH /api/v1/cron/:id are wired through commonHandler (any authenticated user) rather than adminHandler, and the per-server permission check on cron creation has a vacuous-true bypass. A RoleMember user can create a scheduled cron task with Cover=CronCoverAll, Servers=[] and an arbitrary Command. At every tick of the scheduler, the dashboard pushes that command to every server in the global ServerShared map — including servers that belong to other tenants (admin's servers, other members' servers). Each agent runs the command and returns the output, which is then sent to the attacker's own NotificationGroup → attacker-controlled webhook. Net effect: any RoleMember (including a self-bound OAuth2 user, if the dashboard has OAuth2 configured) gets pre-validated cross-tenant RCE on every nezha-monitored host in the deployment. Affected versions Commit…

    Recommended action: Upgrade to 1.14.15-0.20260517022419-d7526351cf97 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →
  13. Medium, CVSS 5.4GoPublished

    Nezha Monitoring: RoleMember can fire other users' cron tasks via AlertRule.FailTriggerTasks (no ownership check)

    CVE-2026-47120 · GHSA-rxf6-wjh4-jfj6

    Affected
    • Go github.com/nezhahq/nezha >= 1.4.0, < 1.14.15-0.20260517022419-d7526351cf97
    Fixed in
    1.14.15-0.20260517022419-d7526351cf97· Vendor fix available
    Issue
    createAlertRule and createService (and their update siblings) accept FailTriggerTasks []uint64 and RecoverTriggerTasks []uint64 — IDs of cron tasks to fire when the alert/service trips. The validation function only validates the alert's Rules.Ignore server map; it never checks that the cron task IDs in FailTriggerTasks / RecoverTriggerTasks belong to the caller. When the alert fires, singleton.CronShared.SendTriggerTasks(taskIDs, triggerServer) (service/singleton/crontask.go:113-127) looks up those task IDs in the global cron registry and executes them via CronTrigger. For non-AlertTrigger cover modes, CronTrigger fans the command out to every server in ServerShared.Range with no ownership check. Net effect: a RoleMember can attach their alert rule (or service monitor) to another user's cron task ID — including admin's crons. When the alert trips, the admin's cron command runs across every server (or every server in its allow/deny list). This is the same fanout/auth-bypass…

    Recommended action: Upgrade to 1.14.15-0.20260517022419-d7526351cf97 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →
  14. High, CVSS 8.5GoPublished

    Nezha Monitoring: RoleMember-reachable SSRF with full response-body reflection via POST /api/v1/notification

    CVE-2026-46717 · GHSA-w4g9-mxgg-j532

    Affected
    • Go github.com/nezhahq/nezha >= 1.4.0, < 1.14.15-0.20260517022419-d06d539d34c1
    Fixed in
    1.14.15-0.20260517022419-d06d539d34c1· Vendor fix available
    Issue
    nezha's dashboard supports two user roles: RoleAdmin (Role==0) and RoleMember (Role==1). The notification routes POST /api/v1/notification and PATCH /api/v1/notification/:id are wired through commonHandler rather than adminHandler — so a RoleMember user can call them. These handlers synchronously Send() an HTTP request to a user-controlled URL and reflect the entire response body (no size limit) back to the caller on any non-2xx response. Net effect: a low-privilege RoleMember can read intranet HTTP response bodies via the dashboard's hub. Affected versions Commit 50dc8e660326b9f22990898142c58b7a5312b42a and earlier on master. Reachability chain For comparison, /user routes ARE gated by adminHandler: adminHandler (controller.go:220-236) explicitly enforces user.Role.IsAdmin(). commonHandler (controller.go:214-218) does not. The vulnerable handler Identical pattern in updateNotification (PATCH /notification/:id) at lines 97-146. The reflection sink The full body (no size…

    Recommended action: Upgrade to 1.14.15-0.20260517022419-d06d539d34c1 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:github.comSource checked Evidence →