BREAKING: CVE-2026-76850 - LMDeploy Pickle RCE in Disaggregated Serving
CVE-2026-76850 is an unauthenticated pickle RCE in LMDeploy's disaggregated-serving peer connector. Versions >=0.9.2 and <0.16.0 are affected. Upgrade to 0.16.0.
Contents
TL;DR: LMDeploy's disaggregated-serving peer connector treats ZMQ peer messages as pickle. The handle_zmq_recv coroutine in lmdeploy/pytorch/disagg/conn/engine_conn.py calls recv_pyobj(), which is pickle.loads() on the received bytes, and only then checks isinstance(..., DistServeCacheFreeRequest). The peer address is caller-controlled: POST /distserve/p2p_connect passes remote_engine_endpoint_info.zmq_address into connect() on the engine's PULL socket. Those HTTP routes apply no authentication unless the server is started with api_keys, which defaults to None. A remote attacker who can reach a disaggregated engine can point it at a hostile ZMQ endpoint and execute code in the engine process. InternLM lmdeploy >=0.9.2 and <0.16.0 is affected. Upgrade to 0.16.0. Deployments that do not enable disaggregated serving are not affected. NVD has not listed this CVE yet. The VulnCheck CNA record scores it 9.3 Critical under CVSS 4.0 (9.8 under CVSS 3.1).
What happened
LMDeploy (PyPI package lmdeploy) is InternLM's toolkit for compressing, deploying, and serving large language models. Prefill-decode disaggregation uses a ZMQ P2P connector so engine nodes can exchange cache-free requests.
That connector had two stacked mistakes.
First, the wire codec was pickle. zmq.Socket.recv_pyobj() deserializes with pickle.loads(). Any object the peer sends is reconstructed, including objects whose __reduce__ method runs arbitrary callables. The isinstance check against DistServeCacheFreeRequest runs after that reconstruction, so it cannot prevent code execution.
Second, the engine does not bind the receive socket and wait for a trusted peer. p2p_connect connects the PULL socket to an address taken from the HTTP request body. POST /distserve/p2p_initialize and POST /distserve/p2p_connect in lmdeploy/serve/openai/api_server.py have no route-level auth and no validate_json_request dependency. AuthenticationMiddleware is installed only when api_keys is passed to serve().
The reachable chain is: an unauthenticated HTTP POST that supplies a zmq_address, the engine's PULL socket connecting outbound to that address, then handle_zmq_recv calling recv_pyobj() on whatever the attacker sends.
AAtomical reported the pickle sink in GitHub issue 4804 on 2026-07-29. A later review on that issue corrected the socket direction: the bound PUSH port is not an inbound pickle oracle. The HTTP-controlled connect path is.
Affected versions
- Package: PyPI
lmdeploy(vendor InternLM) - Affected:
>=0.9.2and<0.16.0(therecv_pyobj()path is present in thev0.9.2andv0.15.0trees) - Fixed:
0.16.0, released 2026-08-19, includes PR 4812 / commitf05b4ad - CWE: CWE-502 (Deserialization of Untrusted Data)
- CVSS: VulnCheck CNA, CVSS 4.0
9.3 Critical(CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N). CVSS 3.19.8 Critical(CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H). NVD has no record yet. Not listed in CISA KEV. - Scope: only engines that enable disaggregated serving. The receive loop starts after the migration backend accepts the connection.
What to do
Upgrade the PyPI package to the fixed release:
pip install --upgrade lmdeploy==0.16.0
Confirm the installed version:
pip show lmdeploy
The Version field should be 0.16.0 or newer. Official install docs also accept pip install lmdeploy now that 0.16.0 is the current PyPI release.
If you cannot upgrade immediately and you run prefill-decode disaggregation, start the API server with API keys so AuthenticationMiddleware covers the /distserve/* routes (those paths are not in the middleware skip list):
lmdeploy serve api_server <model> --api-keys <secret>
--api-keys is a documented server option. Default is None, meaning no key is required. Setting it is a control on the HTTP entry that supplies zmq_address. It is not a substitute for the pickle-to-JSON fix, and InternLM did not publish it as a CVE-specific workaround.
If the cluster does not need disaggregation, leave it disabled. Hybrid / colocated serving does not start this receive loop.
After upgrading, review API-server access logs for unexpected POST /distserve/p2p_initialize and POST /distserve/p2p_connect calls, and keep those routes off the public internet even after the patch.
Technical details
Vulnerable receive path in v0.15.0 engine_conn.py:
self.p2p_receiver[conn_request.remote_engine_id].connect(
conn_request.remote_engine_endpoint_info.zmq_address)
...
req: DistServeCacheFreeRequest = await self.p2p_receiver[remote_engine_id].recv_pyobj()
if isinstance(req, DistServeCacheFreeRequest):
...
The type annotation is cosmetic. Pickle can return any object. The isinstance branch never runs if __reduce__ already executed.
Commit f05b4ad (PR 4812, "fix(disagg): use JSON instead of pickle for P2P ZMQ requests") switches both send_pyobj / recv_pyobj to send_json / recv_json and validates with DistServeCacheFreeRequest.model_validate before use. Decoding is json.loads, which does not execute code. Off-schema messages are logged and skipped so a bad payload cannot tear down the detached receive loop.
That is the correct fix for this class of bug. Adding ZMQ CURVE/ZAP on its own would not close the HTTP-controlled connect path, because the engine would authenticate to whatever endpoint the request named.
No GitHub Security Advisory exists for CVE-2026-76850 as of this writing. HOL Guard's first-seen evidence pack recorded cvssScore: null because NVD has not ingested the record. The scores above come from the published VulnCheck CNA CVE document.
Track the CVE on HOL Guard as more sources land.
References
Continue reading
All posts
CVE-2026-76832: Agno PythonTools Path Traversal Escapes base_dir
CVE-2026-76832 is a CWE-22 path traversal in Agno PythonTools. file_name was joined onto base_dir with no resolved-path check. Upgrade agno to 2.3.24 or later. restrict_to_base_dir=False reopens the hole.

BREAKING: CVE-2026-74764 - Pandora TAR Path Traversal Enables Arbitrary File Write
CVE-2026-74764 is a CVSS 10.0 path traversal in Pandora TAR extraction that lets untrusted archives write outside the analysis directory. v1.12.5 is affected; deploy the upstream fix.

BREAKING: CVE-2026-73043 - SiYuan Template Calculation RCE in Desktop Client
CVE-2026-73043 is a critical SiYuan flaw where unsanitized database Template calculation output reaches Electron innerHTML and can become OS command execution. Upgrade to 3.7.4 or later.
