@anephenix/hub WebSocket RPC Waiter Resource Exhaustion
Any unauthenticated attacker can crash an @anephenix/hub server by opening many WebSocket connections and never responding, causing the server to accumulate unlimited background timers and memory…

The problem
Every incoming WebSocket connection triggers a server-side RPC call to request a client ID via get-client-id. Internally, rpc.send pushes a request object onto this.requests and starts a setInterval that polls every 10 ms waiting for a reply.
The interval is only cleared when a matching response arrives. There is no timeout, and the socket close handler does not cancel pending RPC requests. An attacker who opens connections and never replies causes one leaking timer and one heap object to accumulate per connection, permanently.
Proof of concept
A working proof-of-concept for this issue in @anephenix/hub, with the exact payload below.
node --input-type=module - <<'EOF'
import Hub from './dist/esm/index.js';
import { WebSocket } from 'ws';
const port = 8766;
const hub = new Hub({ port });
hub.listen();
const ws = new WebSocket(`ws://localhost:${port}`);
// Wait for the server's get-client-id RPC message, then close without replying
await new Promise((resolve) => ws.once('message', resolve));
ws.close();
await new Promise((resolve) => setTimeout(resolve, 300));
console.log(JSON.stringify({
serverClients: hub.wss.clients.size, // 0 — socket is gone
pendingRpcRequests: hub.rpc.requests.length, // 1 — leak confirmed
}));
hub.server.close();
process.exit(0);
EOFThe root cause is CWE-400 (Uncontrolled Resource Consumption). In src/lib/rpc.ts, waitForReply starts a setInterval(..., 10) whose only exit path is a matching response arriving in responses[]. No timeout branch exists, and the close event listener registered in loadDefaultConnectionEventListeners only calls pubsub.unsubscribeClientFromAllChannels, so neither the interval reference nor the this.requests entry is ever cleaned up when the socket disconnects.
The patch in v0.2.16 (commits 67260d2 and 931576d) wires a close handler into the RPC layer that calls clearInterval on any in-flight waiter and splices the stale entry out of this.requests when its associated WebSocket closes. This closes the gap between socket lifetime and RPC waiter lifetime.
The fix
Upgrade @anephenix/hub to version 0.2.16 or later. No configuration change is required; the fix is applied automatically by the updated close handler in the RPC layer.
Related research
- high · 7.5CVE-2026-14257CVE-2026-14257: brace-expansion Unbounded Expansion Length DoS (OOM Crash)
- highCVE-2026-55685CVE-2026-55685: react-router Unauthenticated DoS via Inefficient Route Matching on Manifest Endpoint
- highCVE-2026-59880CVE-2026-59880: immutable Hash-Collision Algorithmic Complexity DoS
- high · 7.5CVE-2026-59879CVE-2026-59879: Immutable.js List 32-bit Trie Overflow leading to Denial of Service