CVE-2026-34824
Uncontrolled thread creation in Mesop WebSockets leads to Denial of Service.
- CVSS 7.5
- CWE-770
- Resource Management
- Remote
Mesop is a Python-based UI framework that allows users to build web applications. From version 1.2.3 to before version 1.2.5, an uncontrolled resource consumption vulnerability exists in the WebSocket implementation of the Mesop framework. An unauthenticated attacker can send a rapid succession of WebSocket messages, forcing the server to spawn an unbounded number of operating system threads. This leads to thread exhaustion and Out of Memory (OOM) errors, causing a complete Denial of Service (DoS) for any application built on the framework. This issue has been patched in version 1.2.5.
- CWE
- CWE-770
- CVSS base score
- 7.5
- Published
- 2026-04-03
- OWASP
- A04 Insecure Design
- Orthogonal defect classification
- Timing/Serialization
- Code defect classification
- Missing Check
- Category
- Resource Management
- Subcategory
- Resource Exhaustion
- Accessibility scope
- Remote
- Impact
- Denial of Service (DoS)
- Affected component
- Mesop
- Fixed by upgrading
- Yes
Solution
Upgrade to Mesop version 1.2.5 or later.
Vulnerable code sample
import asyncio
import websockets
import threading
import time
import sys
# This code is a conceptual representation of the vulnerability described
# in CVE-2026-34824. It is not the actual source code from the Mesop framework.
# The purpose is to demonstrate the core flaw: spawning an unbounded number of
# threads in response to WebSocket messages.
def resource_consuming_task(message):
"""
A function that simulates a task that takes time and holds a thread.
In a real-world scenario, this could be a slow I/O operation or
a complex computation.
"""
thread_name = threading.current_thread().name
print(f"New thread '{thread_name}' started to process message of size {len(message)}.")
# Keep the thread alive for a while to simulate work and demonstrate
# how threads can accumulate quickly.
time.sleep(45)
print(f"Thread '{thread_name}' finished processing.")
async def vulnerable_websocket_handler(websocket, path):
"""
This handler contains the vulnerability. For every message received, it
spawns a new OS thread without any limits.
"""
client_address = websocket.remote_address
print(f"Client connected from {client_address}")
try:
# Process messages from the client
async for message in websocket:
# --- VULNERABILITY ---
# A new thread is created for every single incoming message.
# There is no thread pool, queue, or any form of rate limiting.
# An attacker can send messages in a rapid succession, causing
# the server to spawn an unbounded number of threads, leading
# to thread exhaustion and a Denial of Service (DoS).
print(f"Received message from {client_address}. Spawning a new unmanaged thread.")
thread = threading.Thread(
target=resource_consuming_task,
args=(message,),
daemon=True # Daemon threads won't block program exit
)
thread.start()
# The server does not wait for the thread to complete and immediately
# listens for the next message, allowing the attack to proceed rapidly.
except websockets.exceptions.ConnectionClosed:
print(f"Client disconnected from {client_address}")
except Exception as e:
print(f"An error occurred with client {client_address}: {e}")
async def main():
"""
Sets up and runs the vulnerable WebSocket server.
"""
host = "0.0.0.0"
port = 8765
print(f"Starting vulnerable WebSocket server on ws://{host}:{port}")
print("WARNING: This server is designed to demonstrate an uncontrolled resource consumption vulnerability.")
print("Send rapid WebSocket messages to it to trigger the creation of many threads.")
server = await websockets.serve(vulnerable_websocket_handler, host, port)
try:
await server.wait_closed()
except asyncio.CancelledError:
print("Server shutdown initiated.")
server.close()
await server.wait_closed()
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\nServer stopped by user.")
sys.exit(0)Patched code sample
import asyncio
import websockets
import logging
# Configure logging to show that messages are processed sequentially.
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
# This represents the work that needs to be done for each message.
# In the fixed version, this is an async function that is awaited,
# ensuring messages are processed sequentially per connection without
# creating new threads for each message.
async def process_message_safely(message):
"""
Simulates processing a message without blocking the event loop for too long
or creating a new thread.
"""
logging.info(f"Received and started processing message: {message[:30]}...")
# Simulate non-blocking I/O work (e.g., a database query)
await asyncio.sleep(1)
logging.info("Finished processing message.")
async def safe_websocket_handler(websocket, path):
"""
This handler represents the patched version of the code.
It processes incoming WebSocket messages sequentially for each connection.
"""
logging.info(f"Client connected from {websocket.remote_address}")
try:
# The 'async for' loop iterates over messages as they arrive.
async for message in websocket:
# THE FIX:
# Instead of spawning a new OS thread for every incoming message
# (which was the cause of the vulnerability), the server now
# awaits an async processing function. This handles messages
# one by one within the same asyncio task that manages the
# WebSocket connection. This approach prevents unbounded thread
# creation and resource exhaustion, thus mitigating the DoS attack.
await process_message_safely(message)
except websockets.exceptions.ConnectionClosed as e:
logging.info(f"Client disconnected: {e}")
except Exception as e:
logging.error(f"An error occurred in the handler: {e}")
finally:
logging.info(f"Connection closed for {websocket.remote_address}")
async def main():
"""
Sets up and runs the WebSocket server with the fixed handler.
"""
host = "localhost"
port = 8765
async with websockets.serve(safe_websocket_handler, host, port):
logging.info(f"Patched WebSocket server running on ws://{host}:{port}")
# The server will run indefinitely until the program is stopped.
await asyncio.Future()
if __name__ == "__main__":
# To run this server:
# 1. Install websockets: pip install websockets
# 2. Run this Python script: python your_script_name.py
#
# To test the fix, you can use a simple client to send rapid messages.
# The server log will show messages being processed sequentially, not in parallel
# (which would have indicated multiple threads). This demonstrates that a flood
# of messages will queue up for processing rather than causing thread exhaustion.
try:
asyncio.run(main())
except KeyboardInterrupt:
logging.info("Server shutting down.")Cite this entry
@misc{vaitp:cve202634824,
title = {{Uncontrolled thread creation in Mesop WebSockets leads to Denial of Service.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-34824},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-34824/}}
}
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 ::
