File CVE-2025-61765-replace-pickle-with-json.patch of Package python-python-socketio.41063
From 333349c14a614cf5e29f64e9461eb27f9ac2f670 Mon Sep 17 00:00:00 2001
From: Miguel Grinberg <miguel.grinberg@gmail.com>
Date: Wed, 24 Sep 2025 23:56:30 +0100
Subject: [PATCH 1/2] Replace pickle with json
---
src/socketio/async_aiopika_manager.py | 6 +++---
src/socketio/async_pubsub_manager.py | 15 ++++-----------
src/socketio/async_redis_manager.py | 4 ++--
src/socketio/kafka_manager.py | 6 +++---
src/socketio/kombu_manager.py | 4 ++--
src/socketio/pubsub_manager.py | 15 ++++-----------
src/socketio/redis_manager.py | 4 ++--
src/socketio/zmq_manager.py | 10 +++++-----
tests/async/test_pubsub_manager.py | 13 ++++++-------
tests/common/test_pubsub_manager.py | 13 ++++++-------
10 files changed, 37 insertions(+), 53 deletions(-)
Index: python-socketio-5.7.2/src/socketio/kafka_manager.py
===================================================================
--- python-socketio-5.7.2.orig/src/socketio/kafka_manager.py
+++ python-socketio-5.7.2/src/socketio/kafka_manager.py
@@ -1,11 +1,11 @@
import logging
-import pickle
try:
import kafka
except ImportError:
kafka = None
+from engineio import json
from .pubsub_manager import PubSubManager
logger = logging.getLogger('socketio')
@@ -54,7 +54,7 @@ class KafkaManager(PubSubManager): # pr
bootstrap_servers=self.kafka_urls)
def _publish(self, data):
- self.producer.send(self.channel, value=pickle.dumps(data))
+ self.producer.send(self.channel, value=json.dumps(data))
self.producer.flush()
def _kafka_listen(self):
@@ -64,4 +64,4 @@ class KafkaManager(PubSubManager): # pr
def _listen(self):
for message in self._kafka_listen():
if message.topic == self.channel:
- yield pickle.loads(message.value)
+ yield message.value
Index: python-socketio-5.7.2/src/socketio/kombu_manager.py
===================================================================
--- python-socketio-5.7.2.orig/src/socketio/kombu_manager.py
+++ python-socketio-5.7.2/src/socketio/kombu_manager.py
@@ -1,4 +1,3 @@
-import pickle
import uuid
try:
@@ -6,6 +5,7 @@ try:
except ImportError:
kombu = None
+from engineio import json
from .pubsub_manager import PubSubManager
@@ -103,7 +103,7 @@ class KombuManager(PubSubManager): # pr
connection = self._connection()
publish = connection.ensure(self.producer, self.producer.publish,
errback=self.__error_callback)
- publish(pickle.dumps(data))
+ publish(json.dumps(data))
def _listen(self):
reader_queue = self._queue()
Index: python-socketio-5.7.2/src/socketio/pubsub_manager.py
===================================================================
--- python-socketio-5.7.2.orig/src/socketio/pubsub_manager.py
+++ python-socketio-5.7.2/src/socketio/pubsub_manager.py
@@ -2,7 +2,6 @@ from functools import partial
import uuid
from engineio import json
-import pickle
from .base_manager import BaseManager
@@ -154,16 +153,10 @@ class PubSubManager(BaseManager):
if isinstance(message, dict):
data = message
else:
- if isinstance(message, bytes): # pragma: no cover
- try:
- data = pickle.loads(message)
- except:
- pass
- if data is None:
- try:
- data = json.loads(message)
- except:
- pass
+ try:
+ data = json.loads(message)
+ except:
+ pass
if data and 'method' in data:
self._get_logger().info('pubsub message: {}'.format(
data['method']))
Index: python-socketio-5.7.2/src/socketio/redis_manager.py
===================================================================
--- python-socketio-5.7.2.orig/src/socketio/redis_manager.py
+++ python-socketio-5.7.2/src/socketio/redis_manager.py
@@ -1,5 +1,4 @@
import logging
-import pickle
import time
try:
@@ -7,6 +6,7 @@ try:
except ImportError:
redis = None
+from engineio import json
from .pubsub_manager import PubSubManager
logger = logging.getLogger('socketio')
@@ -78,7 +78,7 @@ class RedisManager(PubSubManager): # pr
try:
if not retry:
self._redis_connect()
- return self.redis.publish(self.channel, pickle.dumps(data))
+ return self.redis.publish(self.channel, json.dumps(data))
except redis.exceptions.RedisError:
if retry:
logger.error('Cannot publish to redis... retrying')
Index: python-socketio-5.7.2/src/socketio/zmq_manager.py
===================================================================
--- python-socketio-5.7.2.orig/src/socketio/zmq_manager.py
+++ python-socketio-5.7.2/src/socketio/zmq_manager.py
@@ -1,4 +1,3 @@
-import pickle
import re
try:
@@ -6,6 +5,7 @@ try:
except ImportError:
zmq = None
+from engineio import json
from .pubsub_manager import PubSubManager
@@ -80,14 +80,14 @@ class ZmqManager(PubSubManager): # prag
logger=logger)
def _publish(self, data):
- pickled_data = pickle.dumps(
+ packed_data = json.dumps(
{
'type': 'message',
'channel': self.channel,
'data': data
}
- )
- return self.sink.send(pickled_data)
+ ).encode()
+ return self.sink.send(packed_data)
def zmq_listen(self):
while True:
@@ -99,7 +99,7 @@ class ZmqManager(PubSubManager): # prag
for message in self.zmq_listen():
if isinstance(message, bytes):
try:
- message = pickle.loads(message)
+ message = json.loads(message)
except Exception:
pass
if isinstance(message, dict) and \
Index: python-socketio-5.7.2/tests/common/test_pubsub_manager.py
===================================================================
--- python-socketio-5.7.2.orig/tests/common/test_pubsub_manager.py
+++ python-socketio-5.7.2/tests/common/test_pubsub_manager.py
@@ -1,4 +1,5 @@
import functools
+import json
import logging
import unittest
from unittest import mock
@@ -372,16 +373,14 @@ class TestPubSubManager(unittest.TestCas
self.pm._handle_close_room = mock.MagicMock()
def messages():
- import pickle
-
yield {'method': 'emit', 'value': 'foo'}
yield {'missing': 'method'}
yield '{"method": "callback", "value": "bar"}'
yield {'method': 'disconnect', 'sid': '123', 'namespace': '/foo'}
yield {'method': 'bogus'}
- yield pickle.dumps({'method': 'close_room', 'value': 'baz'})
+ yield json.dumps({'method': 'close_room', 'value': 'baz'})
yield 'bad json'
- yield b'bad pickled'
+ yield b'bad data'
self.pm._listen = mock.MagicMock(side_effect=messages)
try:
Index: python-socketio-5.7.2/src/socketio/asyncio_aiopika_manager.py
===================================================================
--- python-socketio-5.7.2.orig/src/socketio/asyncio_aiopika_manager.py
+++ python-socketio-5.7.2/src/socketio/asyncio_aiopika_manager.py
@@ -1,6 +1,6 @@
import asyncio
-import pickle
+from engineio import json
from socketio.asyncio_pubsub_manager import AsyncPubSubManager
try:
@@ -70,7 +70,7 @@ class AsyncAioPikaManager(AsyncPubSubMan
channel = await self._channel(connection)
exchange = await self._exchange(channel)
await exchange.publish(
- aio_pika.Message(body=pickle.dumps(data),
+ aio_pika.Message(body=json.dumps(data),
delivery_mode=aio_pika.DeliveryMode.PERSISTENT),
routing_key='*'
)
@@ -94,7 +94,7 @@ class AsyncAioPikaManager(AsyncPubSubMan
async with self.listener_queue.iterator() as queue_iter:
async for message in queue_iter:
async with message.process():
- yield pickle.loads(message.body)
+ yield message.body
except Exception:
self._get_logger().error('Cannot receive from rabbitmq... '
'retrying in '
Index: python-socketio-5.7.2/src/socketio/asyncio_pubsub_manager.py
===================================================================
--- python-socketio-5.7.2.orig/src/socketio/asyncio_pubsub_manager.py
+++ python-socketio-5.7.2/src/socketio/asyncio_pubsub_manager.py
@@ -3,7 +3,6 @@ from functools import partial
import uuid
from engineio import json
-import pickle
from .asyncio_manager import AsyncManager
@@ -160,16 +159,10 @@ class AsyncPubSubManager(AsyncManager):
if isinstance(message, dict):
data = message
else:
- if isinstance(message, bytes): # pragma: no cover
- try:
- data = pickle.loads(message)
- except:
- pass
- if data is None:
- try:
- data = json.loads(message)
- except:
- pass
+ try:
+ data = json.loads(message)
+ except:
+ pass
if data and 'method' in data:
self._get_logger().info('pubsub message: {}'.format(
data['method']))
Index: python-socketio-5.7.2/src/socketio/asyncio_redis_manager.py
===================================================================
--- python-socketio-5.7.2.orig/src/socketio/asyncio_redis_manager.py
+++ python-socketio-5.7.2/src/socketio/asyncio_redis_manager.py
@@ -1,5 +1,4 @@
import asyncio
-import pickle
try: # pragma: no cover
from redis import asyncio as aioredis
@@ -12,6 +11,7 @@ except ImportError: # pragma: no cover
aioredis = None
RedisError = None
+from engineio import json
from .asyncio_pubsub_manager import AsyncPubSubManager
@@ -65,7 +65,7 @@ class AsyncRedisManager(AsyncPubSubManag
if not retry:
self._redis_connect()
return await self.redis.publish(
- self.channel, pickle.dumps(data))
+ self.channel, json.dumps(data))
except RedisError:
if retry:
self._get_logger().error('Cannot publish to redis... '
Index: python-socketio-5.7.2/tests/asyncio/test_asyncio_pubsub_manager.py
===================================================================
--- python-socketio-5.7.2.orig/tests/asyncio/test_asyncio_pubsub_manager.py
+++ python-socketio-5.7.2/tests/asyncio/test_asyncio_pubsub_manager.py
@@ -1,5 +1,6 @@
import asyncio
import functools
+import json
import sys
import unittest
from unittest import mock
@@ -431,16 +432,14 @@ class TestAsyncPubSubManager(unittest.Te
self.pm._handle_close_room = AsyncMock()
async def messages():
- import pickle
-
yield {'method': 'emit', 'value': 'foo'}
yield {'missing': 'method'}
yield '{"method": "callback", "value": "bar"}'
yield {'method': 'disconnect', 'sid': '123', 'namespace': '/foo'}
yield {'method': 'bogus'}
- yield pickle.dumps({'method': 'close_room', 'value': 'baz'})
+ yield json.dumps({'method': 'close_room', 'value': 'baz'})
yield 'bad json'
- yield b'bad pickled'
+ yield b'bad data'
raise asyncio.CancelledError() # force the thread to exit
self.pm._listen = messages