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

Nezha's /ws/terminal/:id and /ws/file/:id WebSocket endpoints only check stream UUID existence, letting any authenticated member hijack another user's shell or file manager.

- Payout: Research
- Severity: critical
- Program: Nezha
- Found by: Uhudsavasindankacanokcu2
- Disclosed: 2026-06-26
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-q6xx-5vr8-p898
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-q6xx-5vr8-p898
- Tags: area:web domain:web impact:integrity impact:privesc impact:rce kind:research platform:ghsa sev:critical tech:go tech:websocket technique:source-review vuln:access-control vuln:auth-bypass vuln:idor

**Target:** Dashboard WebSocket endpoints /ws/terminal/:id and /ws/file/:id
**Root cause:** CreateStream stores no creator identity on ioStreamContext, and terminalStream/fmStream authorize solely by GetStream(streamId) existence rather than comparing the caller's uid to the stream owner.
**Steps:**
1. Deploy nezha v2.0.9 with a server; create admin (RoleAdmin, owns server) and member (RoleMember, no access).
2. As admin open web terminal; browser connects to `wss://<dashboard>/ws/terminal/<UUID>`; capture UUID from network inspector, access log, or Referer.
3. As member open `wss://<dashboard>/ws/terminal/<UUID>` with the same UUID.
4. Member's WebSocket attaches to the same ioStreamContext since only `GetStream(streamId)` is checked; read shell output and inject keystrokes.
5. Repeat against `/ws/file/:id` for arbitrary filesystem read/write.
**How found:** Code review of stream lifecycle: noticed CreateStream binds no creator to ioStreamContext and terminalStream/fmStream only validate UUID existence, never comparing getUid(c) to the stream creator.
**Exploitation:** Attacker with any authenticated dashboard account obtains a live stream UUID from a side channel (proxy logs, Referer, browser history, telemetry breadcrumbs), then opens the same WebSocket URL to attach to the victim's ioStreamContext, gaining interactive shell or file-manager control on the target server with no signal to the legitimate owner.
**Escalation:** Cross-tenant: low-privilege RoleMember escalates to shell-level RCE and arbitrary file read/write on servers owned by other users.
**Insight:** When a resource is keyed by an unguessable UUID, check whether the handler validates ownership or merely existence — and audit where that UUID surfaces (URL paths leak into proxy logs, Referer, telemetry), turning a capability token into a cross-tenant hijack.

