WebSocket Security: Vulnerabilities, Attacks, and Testing Guide
A complete technical guide to WebSocket security: cross-site WebSocket hijacking, WS downgrade attacks, message injection, origin validation bypasses, and how to test WebSocket endpoints safely.
Short answer
WebSocket connections bypass the standard HTTP request-security model. Once established, a WebSocket is a persistent bidirectional tunnel that neither the browser nor the server re-authenticates. If the initial handshake is vulnerable to cross-site request forgery, an attacker can open a WebSocket connection as the victim and send or receive arbitrary messages.
The idea in one minute
A WebSocket is like a phone call between the browser and the server. The authentication happens when the call connects — you verify the caller's identity once. After that, every message you exchange over that call is trusted because you already checked who was on the line. The problem: what if an attacker causes the victim's phone to dial the server without the victim knowing? The attacker hides in the room, and every time the server asks "who is this?," the victim (who is still on the call) replies "it's me." The attacker listens to every response and whispers instructions into the victim's ear.
The technical mechanism: a page on evil.com opens a WebSocket to wss://target.com/chat. The browser automatically attaches target.com's cookies to the WebSocket upgrade handshake. If the server does not validate the Origin header, it accepts the connection as authenticated. Evil.com can now send and receive messages through the victim's session.
How WebSocket authentication works
WebSocket connections begin as HTTP requests — the "upgrade handshake":
GET /chat HTTP/1.1
Host: target.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: https://target.com
Cookie: session=abc123
The server responds with 101 Switching Protocols, and from that moment, the connection is a raw TCP tunnel with no further authentication. The server trusts that whoever was authenticated by the HTTP request remains the same entity for the life of the connection.
This trust model has a critical gap: the Cookie header is attached automatically by the browser. If the server only checks the cookie, any cross-origin page can open a WebSocket to the target and the victim's browser will attach the cookies. The server cannot distinguish between the legitimate page and the attacker's page unless it validates the Origin header.
Cross-Site WebSocket Hijacking
The most common and most dangerous WebSocket vulnerability. It is essentially CSRF for WebSocket connections:
- User is authenticated to
target.com. - User visits
evil.com. evil.comexecutes:new WebSocket('wss://target.com/chat').- Browser attaches
target.com's cookies to the handshake. - Server accepts the connection — it sees a valid session cookie.
evil.comsends messages through the socket and reads responses.
The impact depends on what the WebSocket does. If it streams real-time notifications, the attacker reads every notification. If it accepts commands to transfer money, the attacker can initiate transfers. If it exposes internal service data, the attacker can enumerate the infrastructure.
Detection: Open a WebSocket to the target from a different origin (a local HTML file or a page on a different domain). If the connection succeeds without validating the Origin header, the server is vulnerable.
Origin validation bypasses
Servers that do check the Origin header often do it wrong:
- String inclusion:
if (origin.includes("target.com"))— bypassed withhttps://target.com.evil.com - Prefix match:
if (origin.startsWith("https://target.com"))— bypassed withhttps://target.com.evil.com - Suffix match:
if (origin.endsWith("target.com"))— bypassed withhttps://eviltarget.com - Null origin: Some servers accept
Origin: null(sent byfile://pages, data URIs, or sandboxed iframes). An attacker can open a sandboxed iframe that sendsOrigin: null.
WebSocket message injection
Even when the connection is legitimate, the server may trust all incoming messages without authentication. In applications where a WebSocket handles state-changing operations, each message should independently authenticate. Common patterns:
Message from server: {"type": "auth_required", "token": "..."}
Client response: {"type": "auth", "token": "..."}
If the server sends an authentication challenge on connect but then trusts all subsequent messages from that connection, an XSS vulnerability on the page can intercept the auth token and send arbitrary messages through the real socket.
WSS downgrade to WS
Secure WebSocket (WSS) over TLS provides confidentiality and integrity. If the page loads over HTTPS but connects to an insecure WebSocket (ws:// instead of wss://), an attacker on the network can intercept and modify every message. This is mixed content for WebSockets.
Detection: Check the new WebSocket() URL in the page source. If it uses ws:// and the page is served over HTTPS, the connection is vulnerable to network-level interception.
Message format confusion
WebSocket messages can be text or binary. Security logic sometimes differs between the two formats. An API that sanitizes text messages but passes binary messages directly to a parser may have injection vulnerabilities that are only reachable through binary frames.
Verification: real vulnerability or false positive?
A WebSocket connection from a different origin that succeeds is a vulnerability if the connection provides access to authenticated data or state-changing operations. If the server sends a new authentication challenge over the WebSocket (a per-connection token), the CSRF risk is mitigated — but the token must be unpredictable and checked on every message. A static token is not a mitigation.
Real-world impact
In 2019, a cryptocurrency exchange had a WebSocket-based trading API with no Origin validation. An attacker who tricked a trader into visiting a malicious page could place orders through the trader's authenticated WebSocket connection. The vulnerability affected one of the top 10 exchanges by volume and could have been exploited with a single line of JavaScript.
Prevention checklist
- Validate the
Originheader on every WebSocket upgrade handshake. Use an exact match against an allowlist — never substring matching. - Never rely on cookies for WebSocket authentication without Origin validation. Use a per-connection token obtained from a REST API call and passed as the first WebSocket message.
- Enforce WSS-only. Reject plain
ws://connections in production. - Apply per-message authentication for state-changing operations over the WebSocket.
- Rate-limit WebSocket connections per session to prevent resource exhaustion.
- Validate the format and length of every incoming message before processing it.
- Close connections that send invalid or unexpected messages.
Related vulnerabilities
- CSRF — Cross-Site WebSocket Hijacking is CSRF applied to the WebSocket upgrade mechanism.
- CORS — CORS protects XHR/fetch, not WebSockets. A misconfigured CORS policy does not imply a WebSocket vulnerability, and vice versa.
- Origin validation bypasses — The same string-matching mistakes that break CORS also break WebSocket Origin checks.
Testing methodology (do this safely)
Open a WebSocket from a local HTML file to the target using new WebSocket('wss://target.com/path'). If the onopen handler fires, test whether the server validates the Origin header. Send a test message and check whether the response contains data you shouldn't have access to. Always test on your own applications or authorized bug bounty programs. For production targets, use read-only test connections and never send state-changing messages without explicit authorization.
Further reading
- RFC 6455: The WebSocket Protocol
- PortSwigger: WebSocket security
- OWASP: WebSocket Security Testing Guide
- MITRE: CWE-345 — Insufficient Verification of Data Authenticity
Nyxeara perspective
WebSocket connections in the Nyxeara relay system use a Flask-validated bearer token at connect time, not cookies. Origin validation is enforced server-side. The relay lifetime is capped at 15 minutes with a bounded frame queue to prevent resource exhaustion. The Nyxeara verification engine tests WebSocket endpoints for origin validation and WSS downgrade as part of the API security scan — a WebSocket without Origin validation is a high-severity CANDIDATE that triggers a cross-site hijacking verification playbook.