Back to Intelligence

CVE-2026-76850: Critical 9.8 Pickle Deserialization RCE in LMDeploy — Detection and Remediation Guide

SA
Security Arsenal Team
August 19, 2026
9 min read

NVD has published CVE-2026-76850, a CVSS 9.8 CRITICAL, network-exploitable vulnerability in LMDeploy — the inference and serving framework widely used to deploy large language models at scale. The flaw lives in LMDeploy's disaggregated-serving peer-to-peer communication layer and is a textbook unsafe-deserialization bug: incoming peer messages are deserialized with Python's pickle.loads() before any type validation occurs, and the endpoint supplying those bytes is controlled by whoever sends the request.

This is about as bad as it gets for AI infrastructure operators. LMDeploy instances handling disaggregated inference (prefill/decode separation) are typically run on GPU-rich hosts with broad internal network reach — exactly the kind of machine an attacker wants as a first foothold. No authentication, no user interaction, remote code execution with the privileges of the inference server process. If you operate LMDeploy in disaggregated (DistServe) mode, treat this as an emergency patching event and assume the service is reachable by anyone who can touch the port.

Technical Analysis

Affected Component

  • Product: LMDeploy (openai-ecosystem inference serving stack, per the NVD record)
  • Vulnerable code path: handle_zmq_recv coroutine in lmdeploy/pytorch/disagg/conn/engine_conn.py
  • Triggering endpoints: POST /distserve/p2p_initialize and related disaggregated-serving initialization routes
  • CVE / Score: CVE-2026-76850, CVSS 9.8 (CRITICAL), attack vector: NETWORK

How the Vulnerability Works

The disaggregated-serving architecture in LMDeploy splits inference work across multiple engine processes that communicate over ZeroMQ. The vulnerability is a two-step design failure:

  1. Attacker-controlled peer endpoint. When a client calls POST /distserve/p2p_initialize, the server-side p2p_connect logic takes remote_engine_endpoint_info.zmq_address directly from the request body and passes it to connect() on a ZMQ PULL socket. There is no allowlist or validation of that address — the server will happily connect to an endpoint the attacker operates.

  2. Deserialize-then-validate ordering bug. The handle_zmq_recv coroutine reads peer-to-peer cache-free requests using recv_pyobj(), which internally calls pickle.loads() on the received bytes. Only after deserialization completes does the code perform an isinstance check against DistServeCacheFreeRequest. That ordering is fatal: pickle.loads() on attacker-supplied bytes is arbitrary code execution, full stop. The type check is meaningless — by the time it runs, the attacker's __reduce__ payload has already executed.

Attack Chain (Defender's View)

  1. Attacker identifies an exposed LMDeploy instance with disaggregated serving enabled (HTTP API reachable).
  2. Attacker stands up a malicious ZMQ endpoint serving a crafted pickle payload (e.g., one that invokes os.system, spawns a reverse shell, or drops a payload via subprocess).
  3. Attacker sends POST /distserve/p2p_initialize with remote_engine_endpoint_info.zmq_address pointing at the malicious endpoint.
  4. The LMDeploy engine connects its PULL socket to the attacker's endpoint, calls recv_pyobj(), and pickle.loads() executes the payload in the context of the LMDeploy process.
  5. Attacker now has code execution on the GPU host — typically a high-value Linux server with access to model weights, training data, and internal networks.

Exploitation Requirements and Status

  • Authentication: None required.
  • Preconditions: Disaggregated (DistServe) serving mode must be enabled and the HTTP API reachable by the attacker. Pure single-node deployments that never initialize p2p connections are at lower risk, but verify — do not assume.
  • Exploitation status: At the time of writing, check the NVD entry and CISA KEV for current status. Given the CVSS 9.8 score, the trivial reliability of pickle-based RCE, and the growing attacker interest in AI/ML infrastructure, defenders should operate as if exploitation is imminent even before a public PoC surfaces. Pickle deserialization flaws are among the fastest to weaponize once disclosed — the payload mechanics are public knowledge.

Detection & Response

Detection here focuses on three observable behaviors: (1) the LMDeploy server process making outbound ZMQ/network connections to unusual destinations triggered by API requests, (2) the LMDeploy Python process spawning unexpected child processes (the classic post-pickle-RCE artifact), and (3) suspicious inbound calls to the /distserve/ API routes.

Sigma Rules

YAML
---
title: LMDeploy Python Process Spawning Suspicious Child Processes
id: 4f9c2b71-8e3a-4d12-b6f7-2a5c9d1e8f03
status: experimental
description: Detects the LMDeploy inference server Python process spawning shells or command interpreters, consistent with code execution following pickle deserialization exploitation (CVE-2026-76850).
references:
  - https://nvd.nist.gov/vuln/detail/CVE-2026-76850
  - https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.execution
  - attack.t1059.004
logsource:
  category: process_creation
  product: linux
detection:
  selection_parent:
    ParentCommandLine|contains:
      - 'lmdeploy'
      - 'engine_conn'
      - 'distserve'
  selection_child:
    Image|endswith:
      - '/bash'
      - '/sh'
      - '/dash'
      - '/zsh'
      - '/curl'
      - '/wget'
      - '/nc'
      - '/ncat'
      - '/python'
      - '/python3'
      - '/perl'
  condition: selection_parent and selection_child
falsepositives:
  - LMDeploy operational scripts that legitimately invoke subprocesses (rare in serving mode)
level: high
---
title: LMDeploy API Request to Disaggregated Serving p2p Initialization Endpoint
id: 8b2e5d43-1f7a-4c69-9e21-6d3a7b4f0c58
status: experimental
description: Detects HTTP requests to LMDeploy's disaggregated-serving p2p initialization endpoint, the entry point for CVE-2026-76850 exploitation. In environments not using DistServe mode, any such request is suspicious.
references:
  - https://nvd.nist.gov/vuln/detail/CVE-2026-76850
  - https://attack.mitre.org/techniques/T1190/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.initial_access
  - attack.t1190
logsource:
  category: webserver
detection:
  selection:
    cs-uri-stem|contains:
      - '/distserve/p2p_initialize'
      - '/distserve/'
  condition: selection
falsepositives:
  - Legitimate disaggregated-serving cluster initialization traffic
level: medium
---
title: LMDeploy Server Outbound Connection to Non-Cluster Endpoint
id: 2c7a9f16-5d4b-48e3-a193-9f6c2e7d5b41
status: experimental
description: Detects the LMDeploy engine process initiating outbound network connections to external or unrecognized destinations, consistent with p2p_connect being pointed at an attacker-controlled ZMQ endpoint (CVE-2026-76850).
references:
  - https://nvd.nist.gov/vuln/detail/CVE-2026-76850
  - https://attack.mitre.org/techniques/T1071/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.command_and_control
  - attack.t1071
logsource:
  category: network_connection
  product: linux
detection:
  selection:
    Image|contains: 'python'
    CommandLine|contains:
      - 'lmdeploy'
      - 'distserve'
    DestinationIp|cidr:
      - '0.0.0.0/0'
  filter_internal:
    DestinationIp|cidr:
      - '10.0.0.0/8'
      - '172.16.0.0/12'
      - '192.168.0.0/16'
  condition: selection and not filter_internal
falsepositives:
  - Legitimate model downloads or telemetry from the serving host (tune per environment)
level: high

KQL (Microsoft Sentinel / Defender)

The following hunt query targets Syslog/CEF-ingested Linux GPU hosts, looking for the LMDeploy serving process spawning shell children — the highest-fidelity post-exploitation signal:

KQL — Microsoft Sentinel / Defender
// Hunt: LMDeploy process spawning suspicious child processes (CVE-2026-76850 post-exploitation)
let lookback = 7d;
union isfuzzy=true
    (Syslog
    | where TimeGenerated > ago(lookback)
    | where ProcessName =~ "bash" or ProcessName =~ "sh" or ProcessName =~ "curl" or ProcessName =~ "wget"
    | where SyslogMessage has_any ("lmdeploy", "distserve", "engine_conn")
    | project TimeGenerated, Computer, ProcessName, SyslogMessage, HostIP),
    (CommonSecurityLog
    | where TimeGenerated > ago(lookback)
    | where RequestURL has "/distserve/"
    | project TimeGenerated, SourceIP, DestinationIP, RequestURL, RequestMethod, DeviceAction)
| order by TimeGenerated desc

For Defender for Endpoint–onboarded Linux servers:

KQL — Microsoft Sentinel / Defender
// MDE: Network connections and process trees from LMDeploy python processes
DeviceProcessEvents
| where TimeGenerated > ago(7d)
| where InitiatingProcessCommandLine has_any ("lmdeploy", "distserve")
   and (FileName in~ ("bash", "sh", "dash", "curl", "wget", "nc", "python3"))
| project TimeGenerated, DeviceName, FileName, ProcessCommandLine, InitiatingProcessCommandLine, AccountName
| join kind=leftouter (
    DeviceNetworkEvents
    | where TimeGenerated > ago(7d)
    | where InitiatingProcessCommandLine has "lmdeploy"
    | where not(ipv4_is_private(RemoteIP))
    | summarize ExternalConnections=make_set(RemoteIP, 20) by DeviceName, InitiatingProcessId
) on DeviceName, InitiatingProcessId
| order by TimeGenerated desc

Velociraptor VQL

Use this hunt artifact across your GPU/serving fleet to surface LMDeploy processes with unexpected children or unexpected network peers:

VQL — Velociraptor
-- CVE-2026-76850: Hunt LMDeploy processes with suspicious children or network peers
SELECT Pid, Ppid, Name, CommandLine, Exe, Username, CreateTime
FROM pslist()
WHERE CommandLine =~ 'lmdeploy|distserve|engine_conn'
   OR Exe =~ 'lmdeploy'

-- Companion: map listening/connected sockets for those processes
SELECT Pid, Name, Family, Type, Status,
       Laddr AS LocalAddr, Lport AS LocalPort,
       Raddr AS RemoteAddr, Rport AS RemotePort
FROM netstat()
WHERE Name =~ 'python'
  AND (Rport > 0 OR Status =~ 'LISTEN')

Correlate the two result sets by PID: any LMDeploy-owned Python process holding connections to addresses outside your known cluster topology warrants immediate triage.

Remediation Script

This Bash script inventories LMDeploy deployments on a Linux host, flags whether disaggregated serving is in use, and checks the installed version against the fixed release:

Bash / Shell
#!/usr/bin/env bash
# CVE-2026-76850 - LMDeploy pickle deserialization RCE: detection & verification helper
set -euo pipefail

echo "=== CVE-2026-76850 LMDeploy Exposure Check ==="

# 1. Locate LMDeploy installations and report versions
for pyenv in $(command -v python3 python pip3 pip 2>/dev/null); do
    ver=$("$pyenv" -m pip show lmdeploy 2>/dev/null | awk '/^Version/{print $2}') || true
    [ -n "${ver:-}" ] && echo "[FOUND] lmdeploy $ver via $pyenv"
done
find /opt /srv /home /usr/local -maxdepth 6 -type d -name 'lmdeploy' 2>/dev/null | while read -r d; do
    echo "[FOUND] lmdeploy source tree: $d"
done

# 2. Check for running LMDeploy / distserve processes
echo "--- Running processes ---"
ps auxww | grep -Ei 'lmdeploy|distserve|engine_conn' | grep -v grep || echo "No LMDeploy processes running."

# 3. Check for exposed serving ports and recent outbound ZMQ-style connections
echo "--- Listening sockets owned by python ---"
ss -tlnp 2>/dev/null | grep -i python || echo "No python listeners found."
echo "--- Established outbound connections from python (potential p2p peers) ---"
ss -tnp 2>/dev/null | grep -i python | grep ESTAB || echo "No established python connections."

# 4. Audit web access logs for distserve API hits (adjust log paths as needed)
echo "--- Recent /distserve/ API requests ---"
for log in /var/log/nginx/access.log /var/log/apache2/access.log /var/log/haproxy.log; do
    [ -f "$log" ] && grep -h '/distserve/' "$log" | tail -n 20
done
echo "=== Review findings above. Patch or isolate any exposed instance immediately. ==="

Remediation

  1. Upgrade LMDeploy immediately to the version containing the fix referenced in the vendor advisory linked from the NVD entry for CVE-2026-76850. Confirm the patched code path: handle_zmq_recv must validate/authenticate the peer before any pickle.loads() call, and p2p_connect must no longer accept arbitrary zmq_address values from request bodies. Verify the fixed version number against the advisory — do not rely on transitive dependency updates.
  2. Until patched, network-isolate the API. Place the LMDeploy HTTP API behind an authenticated gateway or reverse proxy, restrict /distserve/* routes to trusted cluster IPs only (or block them entirely if you are not using DistServe mode), and enforce mTLS between engines where possible.
  3. Egress control on GPU hosts. Deny outbound connections from inference servers to anything outside an explicit allowlist of cluster peers and model registries. The exploitation chain requires the server to connect out to the attacker's ZMQ endpoint — tight egress policy breaks it even before patching.
  4. Disable disaggregated serving if unused. If your deployment runs single-node inference, ensure DistServe/p2p mode is not initialized. No p2p socket, no attack surface.
  5. Hunt before you patch. Run the queries above across a 7–14 day lookback. A pickle RCE on an internet-adjacent GPU host is a high-value intrusion; if you find evidence of /distserve/ requests from unexpected sources, treat it as an incident: isolate the host, capture memory (LMDeploy processes may still hold attacker payloads), and review for lateral movement from the GPU segment.
  6. Adopt a standing rule for AI/ML stacks: any framework that uses pickle for network messaging should be treated as code-execution-by-design and never exposed beyond a mutually authenticated cluster boundary. Audit your other serving frameworks (Ray, Triton custom backends, vLLM-adjacent tooling) for the same pattern.

Related Resources

Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.