Intelligence
criticalVulnerabilityActive

Nezha WebSocket Stream Hijacking – Cross-Tenant RCE via Missing Ownership Validation

Nezha v1.14.13–v1.14.14 and v2.0.0–v2.0.9 fail to validate stream ownership on WebSocket endpoints, allowing any authenticated user to hijack terminal and file-manager sessions by guessing or obtaining a valid stream UUID, resulting in cross-tenant remote code execution.

S
Sebastion

Affected

nezhahq/nezha v1.14.13–v1.14.14nezhahq/nezha v2.0.0–v2.0.9

Vulnerability Description

The vulnerability is a broken access control flaw in Nezha's WebSocket stream handling. When a user creates a terminal or file-manager session, a stream UUID is generated and stored in memory with no binding to the creator's identity or tenant context. The /ws/terminal/{id} and /ws/file/{id} endpoints authenticate only by UUID presence—checking that the stream exists—but perform no ownership or tenant validation. This allows any authenticated dashboard user (including low-privilege RoleMember accounts) to attach to streams created by other users or tenants. The root cause lies in the CreateStream() function, which allocates an ioStreamContext without recording the creator's identity, and the terminalStream() handler, which retrieves the stream by ID alone without comparing the requester's user context.

Proof-of-Concept Significance

This disclosure demonstrates that the vulnerability requires only: (1) valid dashboard authentication (a low-privilege user role suffices), (2) knowledge or enumeration of a live stream UUID (either via timing attacks, logs, or inference from known patterns), and (3) a single WebSocket connection attempt to the vulnerable endpoint. The PoC is highly reliable because UUIDs, while long, are not cryptographically obscured during transit or in logs, and stream enumeration is feasible in multi-tenant deployments. No additional exploit code is needed—the vulnerability is exploited by connecting to a public endpoint with a guessed or intercepted UUID. The fact that this was silently patched in commit 6661d6a (v2.0.10) without public advisories until now indicates operators running v1.14.x and v2.0.0–v2.0.9 remain unaware of the risk.

Detection Guidance

Log indicators: Search for WebSocket upgrade requests to /ws/terminal/* or /ws/file/* where the authenticated user differs from the stream creator (correlate source IP, session token, or user ID across session logs). Monitor for repeated failed or succeeded WebSocket connections from a single user across multiple stream IDs in short time windows (UUID enumeration). Look for WebSocket sessions initiated by low-privilege roles (e.g., RoleMember) connecting to streams typically created by administrators. Network signatures: Flag WebSocket frames on GET /ws/terminal/ or GET /ws/file/ endpoints lacking an X-User-ID or equivalent ownership header, or where the authenticated principal does not match the stream's creator metadata. YARA/behavioral: Detect code patterns in Nezha deployments that allocate streams without storing user/tenant identity in the context object.

Mitigation Steps

Immediate: Upgrade to Nezha v2.0.10 or later, which includes ownership checks. For v1.14.x users, migrate to v2.0.10+ (v1.14.x is end-of-life and will not receive backports). Workaround (pre-patch): Implement a reverse proxy (nginx, Caddy) that validates stream UUIDs against a allowlist tied to the authenticated user, or add rate limiting and anomaly detection on WebSocket upgrade requests. Configuration hardening: Restrict dashboard access to trusted networks; audit and enforce least-privilege RBAC to minimize the blast radius of a compromised low-privilege account. Detection deployment: Enable comprehensive WebSocket session logging and implement real-time alerts for cross-user stream attachment attempts.

Risk Assessment

This vulnerability is highly likely to be exploited in the wild because: (1) it requires only basic authentication (achievable through credential compromise, insider threat, or supply-chain attacks), (2) it grants immediate interactive access (shell, file control) with no additional steps, (3) it affects two major version branches actively deployed in production (v1.14.x and v2.0.x), and (4) the silent patch suggests the maintainers recognized it as critical. APT groups and ransomware operators targeting infrastructure management platforms will prioritize this. The six-month gap between the fix (May 2026, per the disclosure date notation) and public disclosure represents a window during which adversaries could exploit unpatched systems. Organizations running Nezha in multi-tenant or high-value environments (cloud orchestration, critical infrastructure) are prime targets.