# WebSocket Turbo Intruder: Unearthing the WebSocket Goldmine

Java WebSocket server trusts the frame header payload-length field, allocating a huge buffer and crashing with OutOfMemory when set to Integer.MAX_VALUE.

- Payout: Research
- Severity: high
- Program: Java WebSocket
- Write-up by: PortSwigger Research
- Disclosed: 2025-09-17
- Write-up quality: 6/10
- Original: https://portswigger.net/research/websocket-turbo-intruder-unearthing-the-websocket-goldmine
- Library page: https://bugbountylibrary.com/r/blog%3Aportswigger-net-research-websocket-turbo-intruder-unearthing-the-websocket-goldmine
- Tags: area:web domain:web impact:dos kind:research platform:research sev:high tech:java tech:websocket technique:fuzzing vuln:dos

**Target:** Java WebSocket server frame parser
**Root cause:** The implementation reads the frame header and allocates a buffer sized by the attacker-controlled payload length field before any payload arrives, so a huge declared length exhausts memory.
**Steps:**
1. Open a WebSocket connection to the target using the TURBO engine.
2. Craft a malformed frame whose header payload length field is set to Integer Max Value (2147483647) without sending the corresponding payload.
3. Send the frame; the server allocates a huge buffer and crashes with OutOfMemory.
4. Observe the server no longer responds to any connection attempts.
**How found:** While testing for race conditions with the TURBO engine, the researcher experimented with malformed frames where the declared payload length doesn't match the actual payload (or no payload is sent), and found the Java implementation allocates based on the header value.
**Exploitation:** Attacker sends a single malformed WebSocket frame declaring an Integer.MAX_VALUE payload length; the server pre-allocates the buffer and dies from OOM, taking the service down.
**Insight:** When a protocol lets you declare a length before sending data, try declaring an enormous length with no body; parsers that pre-allocate based on the header (rather than streaming) will OOM. The TURBO engine lets you hand-craft such frames.

## Proof of concept (copied exactly from the original report)

**Socket.IO prototype pollution payload**

```
polluting the initialPacket property with: {"__proto__":{"initialPacket":"Polluted"}}
```

**HTTP middleware POST proxying WebSocket message**

```
POST /proxy?url=https%3A%2F%2F0a7c00a903d17c5a801d35d8008a007a.web-security-academy.net%2Fchat HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 16

{"message":"hi"}
```

**Socket.IO EIO=4 connection script**

```
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"]')
```

