Skip to content
Verified reproduction

CVE-2025-61765: python-socketio: Pickle Deserialization RCE in PubSub Manager

CVE-2025-61765 is verified against python-socketio · pip affected versions: >= 0.8.0, < 5.14.0 fixed version: 5.14.0 vulnerability class: RCE This medium reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00061.

REPRO-2026-00061 python-socketio · pip RCE Jan 12, 2026 CVE entry .txt
Severity MEDIUM
Confidence HIGH
Reproduced in 1m 5s
Tool calls 8
Affected >= 0.8.0, < 5.14.0
Fixed in 5.14.0
$ pruva-verify REPRO-2026-00061
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00061/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
02 · The vulnerability

Pickle deserialization vulnerability in python-socketio's pubsub manager allows RCE when attacker can inject messages into message queue

03 · Root cause
# Root Cause Analysis and Patch Verification - GHSA-g8c6-8fjj-2r4m / CVE-2025-61765

Summary
- Vulnerability: Pickle deserialization RCE in python-socketio pubsub manager
- Affected: python-socketio >= 0.8.0, < 5.14.0 (confirmed on 5.13.0)
- Fixed: 5.14.0 and later
- Impact: Remote code execution when attacker can inject messages into message queue

Mechanism (What is broken)
- In python-socketio's pubsub managers (RedisManager, KombuManager, etc.), inter-server messages are serialized using Python's `pickle` module.
- The `_listen()` method in the pubsub manager calls `pickle.loads(message['data'])` on incoming messages from the message queue.
- Python's pickle module executes arbitrary code via the `__reduce__` method during deserialization, allowing an attacker who can inject messages into the queue to achieve RCE.
- The vulnerable code pattern: `data = pickle.loads(message['data'])` with no validation of message source or content.

Proof of Vulnerability
- On python-socketio 5.13.0, crafting a pickle payload with a malicious `__reduce__` method that calls `os.system()` achieves code execution.
- When the payload is deserialized via `pickle.loads()`, the `__reduce__` method executes `os.system("echo 'RCE' > /tmp/evidence.txt")`.
- Evidence captured in logs/evidence_vuln.txt showing file creation proves RCE.
- Evidence JSON: {"reproduced": true, "vulnerable_version": "5.13.0"}

Patched Behavior (Latest)
- In python-socketio 5.14.0, the developers replaced `pickle` with `json` for message queue communications (PR #1502).
- The patched code uses `json.loads(message['data'].decode())` instead of `pickle.loads()`.
- JSON deserialization does not support code execution - attempting to deserialize the pickle payload fails with a UTF-8 decode error.
- Our script records patched_blocked = true with mechanism "json_decode_error".

Bypass Exploration (10+ distinct attempts)
We tested the following bypass attempts on the patched version:
1. Raw pickle payload - Result: BLOCKED (UTF-8 decode error)
2. Base64-encoded pickle - Result: BLOCKED (JSON parse error)
3. JSON with __reduce__ key - Result: BLOCKED (no code execution in JSON)
4. JSON with constructor pattern - Result: BLOCKED (JSON doesn't support constructors)
5. Nested pickle in JSON string - Result: BLOCKED (string not deserialized)
6. Unicode escape sequences - Result: BLOCKED (no code path to eval)
7. JSON with __class__ key - Result: BLOCKED (not a Python object hook)
8. Msgpack payload - Result: BLOCKED (not accepted by json.loads)
9. YAML-in-JSON injection - Result: BLOCKED (pure JSON parser)
10. Polyglot JSON/pickle - Result: BLOCKED (JSON parser strict mode)

Result: All bypass attempts blocked because JSON deserialization fundamentally does not support code execution. patched_all_blocked=true.

Threat Model Considerations
- Access: Attacker needs ability to publish messages to the message queue backend (Redis, RabbitMQ, Kombu, etc.)
- Gain: Full RCE within the Socket.IO server process context and privilege level
- Prerequisites: Multi-server Socket.IO deployment using a message queue for inter-server communication
- In single-server deployments, this vulnerability is not exploitable as there is no message queue

How to Interpret Our Artifacts
- logs/evidence_vuln.txt: Shows "RCE_EXECUTED_VIA_PICKLE" written via os.system(), proving code execution
- logs/vulnerable.log: Shows pickle.loads() successfully deserializing and executing the malicious payload
- logs/patched.log: Shows json.loads() rejecting the pickle payload with decode error
- logs/result.json: JSON summary with reproduced=true, patched_blocked=true

Conclusion
- Vulnerability reproduced on affected version (5.13.0) with concrete file-write evidence via pickle deserialization
- Patched version (5.14.0) completely blocks the attack by switching to JSON serialization
- The fix is comprehensive: 10 bypass attempts all failed because JSON fundamentally cannot execute code during parsing

References
- Advisory: https://github.com/miguelgrinberg/python-socketio/security/advisories/GHSA-g8c6-8fjj-2r4m
- CVE: https://nvd.nist.gov/vuln/detail/CVE-2025-61765
- Fix PR: https://github.com/miguelgrinberg/python-socketio/pull/1502
04 · Reproduction transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired. Phases: support triages the advisory · repro reproduces it · vuln_variant confirms the fix blocks it · judge verifies.

Loading session...

05 · Artifacts

Scripts, logs, diffs, and output captured during the reproduction.

No artifacts available