---
title: "GHSA-q6xx-5vr8-p898: Nezha vulnerable to cross-tenant terminal/file-manager session hijack via WebSocket stream UUID without ownership check"
url: https://erroneo.us/security/ghsa/GHSA-q6xx-5vr8-p898/
description: "GHSA-q6xx-5vr8-p898 (critical, Go): Nezha vulnerable to cross-tenant terminal/file-manager session hijack via WebSocket stream UUID without ownership check.…"
type: advisory
section: "Security Digest"
date_published: 2026-06-26
date_modified: 2026-06-26
publisher: erroneo.us
author: erroneo.us Security Desk
ghsa: "GHSA-q6xx-5vr8-p898"
license: All rights reserved. Quote with attribution and a link.
---

# GHSA-q6xx-5vr8-p898: Nezha vulnerable to cross-tenant terminal/file-manager session hijack via WebSocket stream UUID without ownership check

## Affected packages

- Go `github.com/nezhahq/nezha` >= 1.14.13, <= 1.14.14 → fixed: none listed
- Go `github.com/nezhahq/nezha` >= 2.0.0, <= 2.0.9 → fixed: 2.0.10

## Details

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/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) 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:// /ws/terminal/ . 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 1. Deploy nezha v2.0.9. Add at least one server. Configure two accounts: admin (RoleAdmin, owns the server) and member (RoleMember, no access to that server). 2. As admin, open the web terminal for the server. The browser opens wss:// /ws/terminal/ . Capture this UUID from the network inspector, server access log, or Referer header. 3. From a separate session logged in as member, open wss:// /ws/terminal/ (same UUID). The member's WebSocket attaches to the same…

## Sources

- [GitHub Advisory GHSA-q6xx-5vr8-p898](https://github.com/advisories/GHSA-q6xx-5vr8-p898)
- [github.com](https://github.com/nezhahq/nezha/security/advisories/GHSA-q6xx-5vr8-p898)

---
Source page: https://erroneo.us/security/ghsa/GHSA-q6xx-5vr8-p898/ · Security Digest: https://erroneo.us/security/ · More: https://erroneo.us/llms.txt
