feat(ws): let WebSocket.connect send handshake headers (#76)
connect(url) could not carry a credential, putting any server that
authenticates the upgrade rather than the first frame out of reach. No
plugin workaround existed: the SDK exposed neither headers nor a
subprotocol.
MAUL surfaced it — /v2/ws is header-only by design (the ?token= fallback
was removed because query strings leak into logs and proxies), so a CS2
plugin could not open an authenticated socket at all.
connect(url, { headers }) is optional, so existing calls are unchanged.
Headers the handshake owns are refused rather than dropped: Host,
Connection, Upgrade, Sec-WebSocket-*, Content-Length, Transfer-Encoding.
Setting one yields a corrupt or spoofed connection rather than a
customised one, and Host specifically is request smuggling against
whatever fronts the target. Control characters in values are refused
because \r\n is how a second header gets injected.
Refusals surface as a rejected connect promise — the same path a bad URL
takes — so a plugin that thinks it authenticated never silently holds an
anonymous socket. G
Gabriel Hirakawa committed
2e7eb80cf7644dd6d6de5e830a97152b8439adc3
Parent: 0ff4b7e
Committed by GitHub <noreply@github.com>
on 8/2/2026, 6:21:04 PM