WebSockets solved a real problem. Before them, real-time web applications relied on long-polling, server-sent events, or other workarounds to push data from server to client. WebSockets provide a persistent, full-duplex connection that is efficient and well-supported by modern browsers.
But that persistent connection also means persistent risk. HTTP security controls -- CSRF tokens, content security policies, rate limiting middleware -- were designed for request-response interactions. WebSockets operate outside that model, and many security teams have not caught up.
The WebSocket Handshake Problem
A WebSocket connection starts as an HTTP upgrade request. The browser sends a standard HTTP request with an Upgrade: websocket header, and the server responds with a 101 status code to switch protocols. After that, the connection is no longer HTTP.
This handshake is where CSRF-like attacks enter the picture. The browser sends cookies automatically with the upgrade request, just like any other HTTP request. If a user is authenticated to your application and visits a malicious page, that page can open a WebSocket connection to your server using the user cookies.
This is called Cross-Site WebSocket Hijacking (CSWSH), and it is one of the most commonly overlooked WebSocket vulnerabilities.
Defending Against CSWSH
Check the Origin header. The browser includes an Origin header in the WebSocket upgrade request. Verify that it matches your expected domain. This is the simplest and most effective defense.
Use a custom authentication token. Instead of relying on cookies for WebSocket authentication, require the client to send an authentication token as the first message after the connection is established. This token should be obtained through your normal authenticated API and should not be accessible to cross-origin scripts.
Do not rely on same-origin policy. Same-origin policy does not prevent WebSocket connections to different origins. Any page can connect to any WebSocket server. The server must validate the connection origin, not the browser.
Message-Level Security
Once a WebSocket connection is established, messages flow in both directions without the HTTP request-response structure. Each message is essentially untrusted input that needs the same validation you would apply to HTTP request bodies.
Input validation is critical. Every message received over a WebSocket should be validated against an expected schema. Do not trust message type fields, lengths, or formats. A compromised client (or a man-in-the-middle attacker) can send arbitrary data over an established WebSocket.
Authorization per message. Just because a user was authorized to open the connection does not mean they are authorized to perform every action available over that connection. Implement per-message authorization checks, especially for WebSocket APIs that support multiple operations.
Rate limiting at the message level. Without rate limiting, a single WebSocket connection can flood your server with messages. HTTP rate limiting middleware typically does not apply to WebSocket messages. You need rate limiting logic within your WebSocket handler.
Denial of Service Vectors
WebSockets open specific denial of service vectors that do not exist in HTTP.
Connection exhaustion. Each WebSocket connection consumes server resources (memory, file descriptors, connection tracking state). An attacker can open thousands of connections and hold them open, exhausting server capacity without sending any messages.
Large message attacks. WebSocket messages can be very large. Without message size limits, an attacker can send multi-gigabyte messages that consume server memory during buffering.
Slow read attacks. An attacker can open a WebSocket connection and read data very slowly, causing the server to buffer increasing amounts of outgoing data. This is the WebSocket equivalent of a Slowloris attack.
Mitigations
Set maximum connection limits per IP address and per authenticated user. Implement message size limits in your WebSocket server configuration. Set idle timeouts to close connections that are not actively sending or receiving data. Monitor WebSocket connection counts as a key infrastructure metric.
Data Exposure Risks
WebSocket connections often carry sensitive data -- chat messages, financial data, user activity streams. The persistent nature of the connection means that data flows continuously rather than in discrete requests.
Encryption is non-negotiable. Always use wss:// (WebSocket Secure) rather than ws://. Unencrypted WebSocket traffic is trivially interceptable, and the persistent connection means an attacker can monitor a continuous stream of data rather than individual request-response pairs.
Message filtering. Ensure your server only sends data that the connected user is authorized to see. In broadcast scenarios (like chat rooms), implement proper access controls to prevent unauthorized users from receiving messages.
Logging and auditing. HTTP access logs naturally capture request-response pairs. WebSocket connections need separate logging to capture message-level activity. Without this, you have no audit trail for actions performed over WebSocket connections.
Proxy and Infrastructure Challenges
WebSocket connections create challenges for network infrastructure that was designed for HTTP.
Load balancers must support WebSocket connections, which are long-lived and stateful. Session affinity (sticky sessions) is often required, which complicates scaling.
Web Application Firewalls (WAFs) typically inspect HTTP requests but may not inspect WebSocket messages. Your WAF configuration needs explicit WebSocket support to provide message-level inspection.
Reverse proxies need specific configuration for WebSocket upgrade handling. Misconfigured proxies may strip the upgrade headers, causing WebSocket connections to fail, or worse, may bypass security checks during the upgrade.
Testing WebSocket Security
Use tools like websocat, wscat, or the browser developer tools to test WebSocket endpoints manually. Automated security scanners often have limited WebSocket support, so manual testing is essential.
Test specifically for: CSWSH by attempting connections from different origins, message injection by sending malformed data, authorization bypass by sending messages that should require different permissions, and DoS resilience by opening many concurrent connections.
How Safeguard.sh Helps
Safeguard.sh monitors the dependencies and frameworks that power your WebSocket implementations. Whether you use Socket.IO, ws, SignalR, or another library, our platform tracks known vulnerabilities in these components and alerts you to security updates. Our SBOM generation captures your real-time communication infrastructure alongside the rest of your supply chain, ensuring no component goes unmonitored.