CVE-2026-62283
Nezha Monitoring: Cross-tenant terminal/file-manager session hijack via WebSocket stream UUID without ownership check
Nezha Monitoring is a self-hostable, lightweight, servers and websites monitoring and O&M tool. Nezha versions 1.14.13 through 1.14.14 and 2.0.0 through 2.0.9 do not bind stream identifiers created by CreateStream in service/rpc/io_stream.go to their creating user, and GET /ws/terminal/:id and GET /ws/file/:id only check whether the supplied UUID exists. An authenticated RoleMember who obtains a live stream UUID from logs, browser history, referer data, or telemetry can attach to another user's terminal or file-manager session, read and write target-server files, and execute shell commands. This issue is fixed in version 2.0.10.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
9.9
Nezha Monitoring: Cross-tenant terminal/file-manager session hijack via WebSocket stream UUID without ownership check
Nezha Monitoring is a self-hostable, lightweight, servers and websites monitoring and O&M tool. Nezha versions 1.14.13 through 1.14.14 and 2.0.0 through 2.0.9 do not bind stream identifiers created by CreateStream in service/rpc/io_stream.go to their creating user, and GET /ws/terminal/:id and GET /ws/file/:id only check whether the supplied UUID exists. An authenticated RoleMember who obtains a live stream UUID from logs, browser history, referer data, or telemetry can attach to another user's terminal or file-manager session, read and write target-server files, and execute shell commands. This issue is fixed in version 2.0.10.
- Record
CVE-2026-62283- CVSS 3.1
- 9.9 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-639, CWE-862
- Updated
- 2026-11-02
EUVDEUVD-2026-64139
9.9
Nezha Monitoring is a self-hostable, lightweight, servers and websites monitoring and O&M tool. Nezha versions 1.14.13 through 1.14.14 and 2.0.0 through 2.0.9 do not bind stream identifiers created by CreateStream in service/rpc/io_stream.go to their creating user, and GET /ws/terminal/:id and GET /ws/file/:id only check whether the supplied UUID exists. An authenticated RoleMember who obtains a live stream UUID from logs, browser history, referer data, or telemetry can attach to another user's terminal or file-manager session, read and write target-server files, and execute shell commands. This issue is fixed in version 2.0.10.
- Record
EUVD-2026-64139- CVSS 3.1
- 9.9 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-q6xx-5vr8-p898
9.9
Nezha vulnerable to cross-tenant terminal/file-manager session hijack via WebSocket stream UUID without ownership check
Summary
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/io_stream.go (v2.0.9):
func (s *NezhaHandler) CreateStream(streamId string) {
s.ioStreamMutex.Lock()
defer s.ioStreamMutex.Unlock()
s.ioStreams[streamId] = &ioStreamContext{
userIoConnectCh: make(chan struct{}),
agentIoConnectCh: make(chan struct{}),
}
}
No creator is bound to the stream.
Stream attach — cmd/dashboard/controller/terminal.go (v2.0.9):
// @Router /ws/terminal/{id} [get]
func terminalStream(c *gin.Context) (any, error) {
streamId := c.Param("id")
if _, err := rpc.NezhaHandlerSingleton.GetStream(streamId); err != nil {
return nil, err
}
defer rpc.NezhaHandlerSingleton.CloseStream(streamId)
// ... WebSocket upgrade and bidirectional pipe ...
}
The only authorization check is GetStream(streamId) — "does this UUID exist in the in-memory map". getUid(c) is never compared against the user who called createTerminal. The same pattern is present in fmStream(c) in cmd/dashboard/controller/fm.go.
Where the UUID leaks:
createTerminal returns the UUID to the legitimate client, which then opens wss://<dashboard>/ws/terminal/<UUID>. As a URL path component the UUID is exposed via:
- Reverse-proxy access logs (nginx, Caddy, Cloudflare).
- Referer headers when the page embeds external resources or error reporters.
- Browser history / bookmark sync.
- Frontend telemetry (Sentry, Bugsnag) breadcrumbs that include the WebSocket URL.
- Any shared-tenant or multi-operator log viewer.
Any authenticated user with access to one of these side channels can attach to a live session.
PoC
- Deploy nezha v2.0.9. Add at least one server. Configure two accounts:
admin(RoleAdmin, owns the server) andmember(RoleMember, no access to that server). - As
admin, open the web terminal for the server. The browser openswss://<dashboard>/ws/terminal/<UUID>. Capture this UUID from the network inspector, server access log, orRefererheader. - From a separate session logged in as
member, openwss://<dashboard>/ws/terminal/<UUID>(same UUID). The member's WebSocket attaches to the sameioStreamContextbecauseterminalStreamonly checksGetStream(streamId)— no ownership check. - The member can now read the admin's shell output and inject keystrokes, achieving shell-level RCE on the target server, with no visible signal to the legitimate session owner.
Same flow works against /ws/file/:id (file-manager hijack: arbitrary read/write on the target server's filesystem).
Impact
- Severity: Critical. Interactive RCE on a server administered by another user, with no audit signal to the rightful session owner.
- Attack complexity: Low. The attacker needs an authenticated dashboard account (which any
RoleMemberis) and one captured UUID from a side channel. - Confidentiality / Integrity / Availability: all High.
/ws/file/:idexposes arbitrary read+write on the target filesystem;/ws/terminal/:idis a full shell.
This is the same impact tier as CVE-2026-46716 (cross-tenant cron RCE) and arguably worse, because…
- Record
GHSA-q6xx-5vr8-p898- CVSS 3.1
- 9.9 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-639, CWE-862
- Updated
- 2026-11-02
NVD
9.9
Nezha Monitoring is a self-hostable, lightweight, servers and websites monitoring and O&M tool. Nezha versions 1.14.13 through 1.14.14 and 2.0.0 through 2.0.9 do not bind stream identifiers created by CreateStream in service/rpc/io_stream.go to their creating user, and GET /ws/terminal/:id and GET /ws/file/:id only check whether the supplied UUID exists. An authenticated RoleMember who obtains a live stream UUID from logs, browser history, referer data, or telemetry can attach to another user's terminal or file-manager session, read and write target-server files, and execute shell commands. This issue is fixed in version 2.0.10.
- Record
CVE-2026-62283- CVSS 3.1
- 9.9 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-639, CWE-862
- Updated
- 2026-11-02
OSV
9.9
Nezha Monitoring: Cross-tenant terminal/file-manager session hijack via WebSocket stream UUID without ownership check
Nezha Monitoring is a self-hostable, lightweight, servers and websites monitoring and O&M tool. Nezha versions 1.14.13 through 1.14.14 and 2.0.0 through 2.0.9 do not bind stream identifiers created by CreateStream in service/rpc/io_stream.go to their creating user, and GET /ws/terminal/:id and GET /ws/file/:id only check whether the supplied UUID exists. An authenticated RoleMember who obtains a live stream UUID from logs, browser history, referer data, or telemetry can attach to another user's terminal or file-manager session, read and write target-server files, and execute shell commands. This issue is fixed in version 2.0.10.
- Record
CVE-2026-62283- CVSS 3.1
- 9.9 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-639, CWE-862
- Updated
- 2026-11-02
OSVGHSA-q6xx-5vr8-p898
9.9
Nezha vulnerable to cross-tenant terminal/file-manager session hijack via WebSocket stream UUID without ownership check
Summary
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/io_stream.go (v2.0.9):
func (s *NezhaHandler) CreateStream(streamId string) {
s.ioStreamMutex.Lock()
defer s.ioStreamMutex.Unlock()
s.ioStreams[streamId] = &ioStreamContext{
userIoConnectCh: make(chan struct{}),
agentIoConnectCh: make(chan struct{}),
}
}
No creator is bound to the stream.
Stream attach — cmd/dashboard/controller/terminal.go (v2.0.9):
// @Router /ws/terminal/{id} [get]
func terminalStream(c *gin.Context) (any, error) {
streamId := c.Param("id")
if _, err := rpc.NezhaHandlerSingleton.GetStream(streamId); err != nil {
return nil, err
}
defer rpc.NezhaHandlerSingleton.CloseStream(streamId)
// ... WebSocket upgrade and bidirectional pipe ...
}
The only authorization check is GetStream(streamId) — "does this UUID exist in the in-memory map". getUid(c) is never compared against the user who called createTerminal. The same pattern is present in fmStream(c) in cmd/dashboard/controller/fm.go.
Where the UUID leaks:
createTerminal returns the UUID to the legitimate client, which then opens wss://<dashboard>/ws/terminal/<UUID>. As a URL path component the UUID is exposed via:
- Reverse-proxy access logs (nginx, Caddy, Cloudflare).
- Referer headers when the page embeds external resources or error reporters.
- Browser history / bookmark sync.
- Frontend telemetry (Sentry, Bugsnag) breadcrumbs that include the WebSocket URL.
- Any shared-tenant or multi-operator log viewer.
Any authenticated user with access to one of these side channels can attach to a live session.
PoC
- Deploy nezha v2.0.9. Add at least one server. Configure two accounts:
admin(RoleAdmin, owns the server) andmember(RoleMember, no access to that server). - As
admin, open the web terminal for the server. The browser openswss://<dashboard>/ws/terminal/<UUID>. Capture this UUID from the network inspector, server access log, orRefererheader. - From a separate session logged in as
member, openwss://<dashboard>/ws/terminal/<UUID>(same UUID). The member's WebSocket attaches to the sameioStreamContextbecauseterminalStreamonly checksGetStream(streamId)— no ownership check. - The member can now read the admin's shell output and inject keystrokes, achieving shell-level RCE on the target server, with no visible signal to the legitimate session owner.
Same flow works against /ws/file/:id (file-manager hijack: arbitrary read/write on the target server's filesystem).
Impact
- Severity: Critical. Interactive RCE on a server administered by another user, with no audit signal to the rightful session owner.
- Attack complexity: Low. The attacker needs an authenticated dashboard account (which any
RoleMemberis) and one captured UUID from a side channel. - Confidentiality / Integrity / Availability: all High.
/ws/file/:idexposes arbitrary read+write on the target filesystem;/ws/terminal/:idis a full shell.
This is the same impact tier as CVE-2026-46716 (cross-tenant cron RCE) and arguably worse, because…
- Record
GHSA-q6xx-5vr8-p898- CVSS 3.1
- 9.9 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-639, CWE-862
- Updated
- 2026-11-02
OSVGO-2026-5821 No score
Nezha vulnerable to cross-tenant terminal/file-manager session hijack via WebSocket stream UUID without ownership check in github.com/nezhahq/nezha
Nezha vulnerable to cross-tenant terminal/file-manager session hijack via WebSocket stream UUID without ownership check in github.com/nezhahq/nezha.
NOTE: The source advisory for this report contains additional versions that could not be automatically mapped to standard Go module versions.
(If this is causing false-positive reports from vulnerability scanners, please suggest an edit to the report.)
The additional affected modules and versions are: github.com/nezhahq/nezha from v2.0.0 before v2.0.10.
- Record
GO-2026-5821- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
github.com/nezhahq/nezhaGo |
1.14.13 to 1.14.14 | None known |
github.com/nezhahq/nezhaGo |
2.0.0 to 2.0.9 | 2.0.10 |
github.com/nezhahq/nezhaGo |
2.0.0 up to 2.0.10 | 2.0.10 |
github.com/nezhahq/nezhaGo |
All versions | None known |
github.com/nezhahq/nezhaGo |
1.14.13 and later | None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-62283 is a critical vulnerability (CVSS 9.9) in Nezhahq Nezha, published June 26, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.55%, the 46th percentile. Fixed in github.com/nezhahq/nezha 2.0.10.
References
github.com/nezhahq/nezha/security/advisories/GHSA-q6xx-5vr8-p898
github.com/nezhahq/nezha/commit/6661d6a7fc1c269f55c7f4e775082ad23fbe0f54
github.com/nezhahq/nezha/releases/tag/v2.0.10
github.com/advisories/GHSA-q6xx-5vr8-p898
github.com/CVEProject/cvelistV5/tree/main/cves/2026/62xxx/CVE-2026-62283.json
nvd.nist.gov/vuln/detail/CVE-2026-62283
github.com/nezhahq/nezha
Left out here: the rest of 2 source descriptions. The JSON record has them.