API Key Exposed in WebSocket Query Parameters
WebSocket gateways accepted partner API keys via the `?apiKey=` handshake query string, leaking live credentials into access logs, reverse-proxy logs, and browser history. Public partner integration docs actively recommended the leaking form.
Description
The PartnerPositionWebSocketGateway accepts API keys via the apiKey query parameter in the WebSocket handshake URL. While the gateway also supports the Authorization header (L89-L94), the query parameter path is checked first and is the primary documented method (L84-L87).
// partner-position-websocket.gateway.ts L83-L97private extractApiKey(client: Socket): string | undefined {const queryApiKey = client.handshake.query.apiKey; // checked firstif (typeof queryApiKey === "string" && queryApiKey.length > 0) {return queryApiKey; // API key in URL: wss://...?apiKey=dm_live_skey_SECRET}const authHeader = client.handshake.headers.authorization;if (typeof authHeader === "string") {if (authHeader.startsWith(apiKeyAuthHeaderPrefix)) {return authHeader.slice(apiKeyAuthHeaderPrefix.length);}}return undefined;}
Frontend / on-chain mitigation analysis: The frontend controls which authentication method is used. If the partner's frontend exclusively uses the Authorization header (L89-L94), no key appears in URLs. However, the backend actively supports and prioritizes the query parameter method, and partners integrating directly may default to this pattern since many WebSocket client libraries make query params easier than custom headers. The backend should enforce the secure path regardless of frontend behavior.
Impact
API key leakage through server logs, proxy logs, and browser history.
Recommendation
Remove query parameter API key support entirely. Require API keys exclusively via the Authorization header. If query parameter auth is needed, implement a short-lived single-use ticket exchange.
Resolution
Fixed in PR #3685, the query-string carrier was removed entirely; auth payload + Authorization header are now required.

