highCWE-346OWASP A01:2021

WebSocket Missing Origin Validation

A WebSocket server that does not check the Origin header accepts connections from any website, allowing cross-site WebSocket hijacking where a malicious page connects to your WS endpoint using the victim's authenticated session.

How It Works

Unlike HTTP requests, WebSocket connections are not subject to the same-origin policy. Any website can open a WebSocket connection to any server. The browser includes the user's cookies in the WebSocket handshake automatically. If the WS server does not validate the Origin header, a malicious website can establish a connection using the victim's session cookies. This is called Cross-Site WebSocket Hijacking (CSWSH). The attacker's page at evil.com opens a WebSocket to your-app.com/ws, the browser sends the user's auth cookies, and the server accepts the connection thinking it is legitimate. The attacker can then send and receive messages as the authenticated user -- reading private data, sending commands, or modifying state in real time.

Vulnerable Code
// BAD: WebSocket server accepts connections from any origin
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });

server.on('connection', (ws, req) => {
  // No origin check -- any website can connect
  // Attacker's page at evil.com can connect using victim's cookies
  ws.on('message', (data) => {
    const msg = JSON.parse(data);
    handleMessage(ws, msg); // processes attacker's commands as victim
  });
});
Secure Code
// GOOD: validate Origin header and authenticate the connection
const WebSocket = require('ws');
const ALLOWED_ORIGINS = ['https://myapp.com', 'https://www.myapp.com'];
const server = new WebSocket.Server({
  port: 8080,
  verifyClient: (info, callback) => {
    const origin = info.origin || info.req.headers.origin;
    if (!ALLOWED_ORIGINS.includes(origin)) {
      callback(false, 403, 'Forbidden: invalid origin');
      return;
    }
    // Also verify auth token from query string or first message
    callback(true);
  }
});

server.on('connection', (ws, req) => {
  ws.on('message', (data) => {
    const msg = JSON.parse(data);
    handleMessage(ws, msg);
  });
});

Real-World Example

In 2018, security researchers discovered that Slack's desktop application had a Cross-Site WebSocket Hijacking vulnerability. Because the WebSocket server did not properly validate the Origin header, a malicious website could connect to the local Slack WebSocket API, steal tokens, and exfiltrate messages. Slack patched the issue after responsible disclosure, but it affected all users running the desktop app.

How to Prevent It

  • Always validate the Origin header in the WebSocket handshake using verifyClient and reject connections from unexpected origins
  • Do not rely solely on cookies for WebSocket authentication -- use a token passed in the connection URL or first message that is verified server-side
  • Implement CSRF tokens for the initial WebSocket handshake endpoint to prevent cross-site connection initiation
  • Use wss:// (WebSocket Secure) exclusively to prevent man-in-the-middle interception of the WebSocket handshake and traffic

Affected Technologies

Node.jsPythonGo

Data Hogo detects this vulnerability automatically.

Scan Your Repo Free

Related Vulnerabilities