The fixed-target WebSocket egress relay (crates/egress-relay) spawns one unbounded thread per accepted connection, and serve_connection's ws.read() blocks indefinitely with no idle/read timeout. A client that connects, sends a valid hello, then goes silent pins a thread + its backend socket forever; many such connections exhaust threads/FDs.
This is the abuse risk the design spec flagged as in-scope-before-public-deploy. The MVP is safe behind a non-public bind, but this must be closed before the relay is exposed (Task 6 live demo).
Fixes to make:
- per-IP connection cap
- idle / read timeout on
ws.read()
- wire a real
tracing subscriber so the "rejected egress target" security log actually surfaces (currently a NoSubscriber stub swallows it)
Ref: docs/superpowers/specs/2026-07-04-browser-egress-ws-relay-design.md (Non-goals / risks).
The fixed-target WebSocket egress relay (
crates/egress-relay) spawns one unbounded thread per accepted connection, andserve_connection'sws.read()blocks indefinitely with no idle/read timeout. A client that connects, sends a valid hello, then goes silent pins a thread + its backend socket forever; many such connections exhaust threads/FDs.This is the abuse risk the design spec flagged as in-scope-before-public-deploy. The MVP is safe behind a non-public bind, but this must be closed before the relay is exposed (Task 6 live demo).
Fixes to make:
ws.read()tracingsubscriber so the "rejected egress target" security log actually surfaces (currently aNoSubscriberstub swallows it)Ref: docs/superpowers/specs/2026-07-04-browser-egress-ws-relay-design.md (Non-goals / risks).