// threat brief
SGLang disaggregated diffusion pickle deserialization: anyone who can reach the ZeroMQ port can run code
- CVSS
- 9.8 CRITICAL
- CISA KEV
- Not listed
- Weakness
- CWE-502
- Topics
- AI security
AI review 2026-09-28 (not human-reviewed)Command tests: none yetReproduced: not yetVerification record ↓
SGLang's disaggregated DiffusionServer unpickles network messages with no login, so anyone who can reach its port can run code. No fixed version yet.
| Who is affected | SGLang deployments running disaggregated diffusion mode (head node started with --disagg-role server), version 0.5.11 or later. The CVE record currently lists 0.5.11 through 0.5.14; the researcher gives evidence that later versions are still affected; PlainCVE's source check on 2026-09-24 found that v0.5.20 and that day's main still call pickle.loads() directly. Remote attack requires the ZeroMQ port to be reachable over the network. |
|---|---|
| What happens | Any host that can reach the head node's ZeroMQ frontend port can run arbitrary code inside the DiffusionServer process without credentials. |
| What to do now | No fixed version yet. PlainCVE's analysis (from reading the code, not tested): restrict who can reach the head node's ZeroMQ ports. On a single host you can consider leaving --host unset so it binds to 127.0.0.1; across hosts that would stop remote workers from connecting back, so use an isolated private network and a firewall that allows only known nodes instead. Restrict encoder workers too. |
| Affected versions | The CVE record (CERT/CC) currently lists 0.5.11 through 0.5.14 (OSV and Strix match; NVD has not analysed it and lists no range); the researcher gives evidence that later versions are still affected (verified on 0.5.17, and says 0.5.11 through 0.5.20 and main all have it); PlainCVE's source check on 2026-09-24 found v0.5.20 still calls pickle.loads() directly |
| Fixed versions | No fixed version yet |
| CVSS vector | Show full vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Timeline |
|
Blue team playbook
Check, fix / mitigate, respond, harden. Matching the affected versions does not mean you were compromised, and a check that finds nothing does not prove you are safe; each item says what it can and cannot show. Tagged steps point to where the attack flow below can be stopped.
- 01Check your version and whether you use disaggregated diffusion
You are affected if you run 0.5.11 or later and the head node is started with --disagg-role server. The CVE record currently lists only up to 0.5.14, but the researcher gives evidence that later versions are still affected, and PlainCVE's source check on 2026-09-24 found the same call in v0.5.20. Until a confirmed fixed version exists, PlainCVE suggests counting every version from 0.5.11 up as affected in your inventory; this is a conservative inventory policy and does not cover future fixed versions. Run pip show in the environment that actually runs the service (the same venv or container), or you may see a different version.
Read-only checkpip show sglang | grep -i '^version'; pgrep -af -- '--disagg-role' - 02Check which address the head node binds to
If the command line has --host 0.0.0.0 or another non-loopback address, the ZeroMQ frontend is exposed to the network; without --host it binds only to 127.0.0.1. There is no separate flag for the ZeroMQ address; both the frontend port and the ports that receive worker results follow the HTTP --host setting. ss only lists what is listening on this machine and does not by itself prove the port is reachable from outside; that also depends on firewalls and network setup.
Read-only checkss -ltnp | grep -v '127.0.0.1' - 03Don't forget the encoder workers
A separate finding from the researcher (not part of this CVE): encoder workers bind to 0.0.0.0 regardless of --host and also call pickle.loads(). Checking only the head node is not enough.
- 04Look for suspicious connections
The sources publish no indicators of compromise. PlainCVE suggests checking for connections to the ZeroMQ frontend port from hosts outside the cluster, and for unexpected child processes or outbound connections from the DiffusionServer process.
- 01Restrict network reachability (no fixed version yet)
No vendor workaround is documented. PlainCVE's analysis (from reading the v0.5.20 code, not tested): --host sets the bind address for HTTP, the ZeroMQ frontend port and the ZeroMQ ports workers use to return results. On a single host or within one network namespace, you can consider leaving --host unset so it binds to 127.0.0.1. Across hosts, binding to 127.0.0.1 stops remote workers from returning results; instead put the nodes on an isolated private network, firewall the necessary ports to known nodes only, and confirm worker traffic still works. A reverse proxy in front of HTTP does not cover the ZeroMQ ports. Note that the official guide shows --host 0.0.0.0.
- 02Firewall the encoder workers
PlainCVE's analysis (not verified): because encoder workers bind to 0.0.0.0 regardless of --host, use a host or network firewall to restrict who can reach them.
- 03Track the upstream fix
Community fix PR #30804 was closed by a bot without being merged. Maintainer PR #40259 only changed the SafeUnpickler allowlist in python/sglang/srt/utils/common.py and did not touch orchestrator.py in multimodal_gen; PlainCVE's source check on 2026-09-24 found that v0.5.20 and that day's main still call pickle.loads() directly.
- 01Suspicious activity: investigate as a possible compromise
PlainCVE suggests: unfamiliar connections alone do not prove compromise; they may be scans or junk traffic. First check the DiffusionServer process for unknown child processes, unusual outbound connections or other signs of code execution. If that evidence is there, since the attacker could run any code in the process, isolate the host, rebuild from a clean image and rotate any credentials and keys the process could reach. This is a precaution; the sources give no incident response guidance.
- 01Keep inference cluster internal ports off public networks
Put node-to-node ports on an isolated internal network and expose only the APIs you need.
- 02Developers: never unpickle network data
Use plain data formats such as JSON across machines, and authenticate the sender first.
Full remediation steps and notes
There is no fixed version to upgrade to. PlainCVE’s suggestion (not a verified mitigation) is to restrict network access. PlainCVE’s additional notes:
--hostsets the bind address for both HTTP and ZeroMQ (from reading the v0.5.20 code, not tested). Inlaunch_disagg_server(), the ZeroMQ frontend port (--scheduler-port) and the ports that receive worker results (--scheduler-portplus 1 to 3) all use the--hostvalue, with no separate flag. So it depends on your setup:- Single host or one network namespace: you can consider leaving
--hostunset so it binds to 127.0.0.1. The HTTP API then also becomes local-only, so you’ll need something like a reverse proxy to serve it externally; the reverse proxy protects only HTTP, not the ZeroMQ ports. - Across hosts: binding to 127.0.0.1 stops remote workers from sending results back to the head node. Put the nodes on an isolated private network, firewall the necessary ports (frontend and result ports) to known nodes only, and confirm worker traffic still works afterwards.
- Single host or one network namespace: you can consider leaving
- The official guide’s example is itself exposed. If you followed SGLang’s disaggregation guide and used
--host 0.0.0.0, deal with that first. - Take a broad view when inventorying. The CVE record currently lists 0.5.11 through 0.5.14; the researcher gives evidence for later versions; our source check found v0.5.20 still has the call. Until a confirmed fixed version exists, count 0.5.11 and later as affected. This is a conservative inventory policy as of 2026-09-24 and does not cover future fixed versions.
- Fix status. Community PR #30804 named this issue as one it would fix, but a bot closed it as idle without merging. Maintainer PR #40259 only changed
python/sglang/srt/utils/common.py, tightening which classes SafeUnpickler allows; it did not touchorchestrator.pyinmultimodal_gen. PlainCVE’s source check on 2026-09-24 found that_handle_client_request()in v0.5.20 and that day’s main still callspickle.loads()directly. The GitHub Advisory Database entry is still unreviewed and lists no fixed version.
Attack flow
Read left to right: this is the order the attack happens in. A blue shield means the step can be stopped; the earlier, the better. Click an icon for details.
Read top to bottom: this is the order the attack happens in. A blue shield means the step can be stopped; the earlier, the better. Tap an icon for details.
- Attacker
Finds a reachable DiffusionServer ZeroMQ frontend port
The port is reachable from the network only if the head node is bound to a non-loopback address with --host. SGLang's own disaggregation guide uses --host 0.0.0.0 (all network interfaces).
Defense: PlainCVE's analysis (from reading the code, not tested): on a single host, consider leaving --host unset (binds to 127.0.0.1); across hosts, use an isolated network and a firewall that allows only known nodes.
- Attacker
Connects to the ROUTER socket with no credentials
The ZeroMQ socket has no authentication and accepts connections from any client.
Defense: Allow only trusted cluster nodes at the network layer.
- Attacker
Sends a multipart message whose last part carries malicious serialized data
The server treats the last part of every multipart message as pickle data.
- Your system
The server calls pickle.loads() before any checks
Loading pickle data can trigger actions named inside the data, so loading untrusted data lets the sender give orders.
Defense: No fixed version yet; the real fix is not using pickle for network messages, or authenticating the sender first.
- Your system
The attacker's code runs inside the DiffusionServer process
What the attacker can do depends on the process's privileges and what it can reach.
Defense: Run the service with a least-privilege account and isolate it on the network.
Who is affected
Remote exploitation requires all of these: disaggregated diffusion mode (head node started with --disagg-role server), an affected version, and a ZeroMQ frontend port reachable from the network.
| Condition | Affected? |
|---|---|
| 0.5.11 to 0.5.14 + disaggregated diffusion mode | Affected (the CVE record, OSV, Strix and the researcher agree) |
| 0.5.15 to 0.5.20, current main | Not listed in the CVE record, but not safe: the researcher gives evidence and confirmed the flaw on 0.5.17; PlainCVE’s source check on 2026-09-24 found v0.5.20 and that day’s main still call pickle.loads() directly |
Head node set with --host 0.0.0.0 or another non-loopback address | Attackable over the network; SGLang’s official guide shows exactly this |
--host left unset (binds to 127.0.0.1) | Reachable only by processes on the same machine; in a cross-host deployment, remote workers can’t connect back either (from reading the code, not tested) |
| Not using disaggregated diffusion mode | This CVE’s precondition is not met; but the CVE record for a separate flaw, CVE-2026-7301 (published 2026-05-18), says the multimodal generation runtime scheduler’s ROUTER socket binds to 0.0.0.0 by default and also calls pickle.loads() on incoming messages, so assess it separately |
| Every version as of 2026-09-24 | No fixed version yet |
The researcher also found a related problem that is not part of this CVE: encoder workers bind to 0.0.0.0 no matter what --host says, and they also call pickle.loads(). So binding the head node to 127.0.0.1 alone does not make the deployment safe.
How it works
SGLang’s multimodal generation feature can split the work of a diffusion model (a model that generates images and similar content) across several machines, coordinated by a DiffusionServer on the head node. The nodes talk through ZeroMQ, a library for passing messages between programs over the network.
The problem has two layers:
- No authentication. The DiffusionServer’s ZeroMQ ROUTER socket accepts connections from any client without checking who it is.
- Unpickling outside data. When the server receives a multipart message, it hands the last part straight to Python’s
pickle.loads(), before any checks. pickle is Python’s object serialization format, and loading it can trigger actions named in the data, so unpickling data from a stranger lets them run code in your process. This kind of mistake is CWE-502 (Deserialization of Untrusted Data).
Put together: any host that can open a TCP connection to the port can run arbitrary code inside the DiffusionServer process. CISA’s SSVC assessment rates it automatable, with total technical impact.
The flawed approach (conceptual illustration, not the original source code):
Show code example(python)
frames = router_socket.recv_multipart() # anyone can connect
request = pickle.loads(frames[-1]) # loaded before any checkA safer approach (PlainCVE’s illustration; there is no fixed version yet):
Show code example(python)
frames = router_socket.recv_multipart()
request = json.loads(frames[-1]) # accept plain data only
validate(request) # then check the contentsTimeline
| Date | Event |
|---|---|
| 2026-04-16 | According to the researcher, commit 9da998a8 (PR #21701, disaggregated diffusion feature) adds orchestrator.py, introducing the problem |
| 2026-07-03 | Researcher reports privately via GitHub Security Advisory (GHSA-8374-wrr5-7q7f) |
| 2026-07-10 | Community PR #30804 publicly lists “disaggregation orchestrator accepts external pickle payloads”: the issue was visible in a public PR before the CVE was published |
| 2026-08-11 | Researcher opens public tracking issue #34419, noting more than five weeks with no maintainer response |
| 2026-08-14 | Reported to CERT/CC (VINCE, VU#727584) |
| 2026-09-17 | CERT/CC verifies the flaw and assigns the CVE |
| 2026-09-19 | Community fix PR #30804 closed unmerged; maintainer PR #40259 merged (changes only srt/utils/common.py, not orchestrator.py) |
| 2026-09-22 | CVE published |
| 2026-09-24 | Still not in CISA KEV (catalog version 2026.09.23), and no fixed version; PlainCVE’s source check finds main still calls pickle.loads() directly |
Further reading
- Scoring: the 9.8 (CVSS 3.1) score comes from CISA’s ADP, not the CNA (CERT/CC). NVD still lists the CVE as “Awaiting Analysis”.
- Affected versions: the CVE record currently lists 0.5.11 through 0.5.14 (OSV and Strix match; NVD has not analysed it and lists no range); the researcher gives evidence for later versions; our source check found v0.5.20 still has the call. OSV’s starting commit (612785ff…) differs from the researcher’s 9da998a8 and may simply be the 0.5.11 release commit.
- Public PoC: the researcher published the core PoC snippet (a harmless version that only prints a marker), the verification method and its output, and CISA’s SSVC in the CVE record rates Exploitation as poc; whether a complete, ready-to-run tool also exists has not been verified. TheHackerWire says no public exploit code has been confirmed, which conflicts with the above.
- Exploitation: not in KEV as of 2026-09-24 (catalog version 2026.09.23). The sources have no evidence either way on exploitation in the wild or before a patch; not being in KEV does not prove it hasn’t been exploited.
- Related weakness type: CWE-502.
Verification Checked item by item against sources by AI under our review rules, all passed; not human-reviewed and not yet reproduced in our lab
| AI review | 2026-09-28 · review rules |
|---|
Verification records describe the environment and the result only, never reproduction steps or code that could attack other people’s systems. See our policy.
Sources
- AdvisoryCVE-2026-93088 Record (CVE Services API) · CVE Program / CERT/CC, 2026-09-22 · accessed 2026-09-24
- CVE / NVD / OSVNVD API - CVE-2026-93088 · NIST · accessed 2026-09-24
- OtherOSV - CVE-2026-93088 · OSV · accessed 2026-09-24
- AdvisoryGitHub Advisory Database - CVE-2026-93088 (unreviewed) · GitHub · accessed 2026-09-24
- ResearchSGLang CVE-2026-93088 write-up · Keita Sode (SYZD Research) · accessed 2026-09-24Contains demonstration code (a harmless marker PoC); CISA tags this URL as "exploit" in the CVE record
- Othersglang issue #34419 (public tracking issue) · sgl-project (GitHub), 2026-08-11 · accessed 2026-09-24
- Othersglang PR #30804 (community fix, closed unmerged) · sgl-project (GitHub), 2026-09-19 · accessed 2026-09-24
- Othersglang PR #40259 (SafeUnpickler allowlist) · sgl-project (GitHub), 2026-09-19 · accessed 2026-09-24
- VendorSGLang Diffusion disaggregation guide · SGLang · accessed 2026-09-24
- OtherCVE-2026-93088 · Strix · accessed 2026-09-24
- NewsCVE-2026-93088 · TheHackerWire · accessed 2026-09-24
- Othersglang v0.5.20 orchestrator.py (DiffusionServer._handle_client_request) · sgl-project (GitHub) · accessed 2026-09-24
- Othersglang v0.5.20 launch_server.py (launch_disagg_server endpoints) · sgl-project (GitHub) · accessed 2026-09-24
- Othersglang main a69583f orchestrator.py · sgl-project (GitHub) · accessed 2026-09-24
- Othersglang PR #40259 changed files · sgl-project (GitHub) · accessed 2026-09-24
- OtherCISA Known Exploited Vulnerabilities Catalog (version 2026.09.23) · CISA · accessed 2026-09-24
Press brief
In one sentence
SGLang is an open-source framework for running AI models. Its 'disaggregated diffusion' mode for multimodal generation such as images has a critical flaw: the server loads data received from the network with Python's pickle, with no login required, so anyone who can reach the port can run code on the server. CISA scored it CVSS 9.8. As of September 24, 2026, no fixed version has been released.
Key facts
- Severity
- CVSS 3.1 9.8 (CISA ADP); NVD not yet analysed cveawg.mitre.org
- CVE published
- 2026-09-22 cveawg.mitre.org
- Fixed version
- No fixed version yet (the CVE record lists no fixed version) cveawg.mitre.org
- Credited to
- Keita Sode (SYZD Research) cveawg.mitre.org
- Weakness
- CWE-502 Deserialization of Untrusted Data cveawg.mitre.org
Confirmed
- The DiffusionServer's ZeroMQ ROUTER socket has no authentication and calls pickle.loads() on received data before any checks.
- As of the researcher's write-up, the latest release and main still contain the vulnerable code; there is no fixed version.
- PlainCVE's source check on 2026-09-24: _handle_client_request() in v0.5.20 and that day's main still calls pickle.loads() directly.
- Maintainer PR #40259 only changed srt/utils/common.py and did not touch the pickle.loads() in orchestrator.py.
- The researcher published the core PoC snippet, the verification method and its output; CISA's SSVC in the CVE record rates Exploitation as poc.
- Not in CISA KEV as of 2026-09-24 (catalog version 2026.09.23); not being listed does not mean it has not been exploited.
Unconfirmed / disputed
- Whether the CVE record will update its affected range (currently 0.5.11 through 0.5.14), and when an official fixed version will be released.
- The core PoC snippet and verification results have been published; whether a complete, ready-to-run tool also exists has not been verified.
- Whether it has been exploited in the wild: no evidence either way; not being in KEV does not prove it hasn't been.
Quotable line
Unpickling data from strangers is like letting a stranger's note tell your computer what to do.
Images
Download the share image (PNG) · Attack flow diagram (downloadable)
Please credit "PlainCVE" and link to this page. Full citation format is under "How to cite" below. Found a factual error? Report it.
SGLang disaggregated diffusion pickle deserialization: anyone who can reach the ZeroMQ port can run code SGLang is an open-source framework for running AI models. Its 'disaggregated diffusion' mode for multimodal generation such as images has a critical flaw: the server loads data received from the network with Python's pickle, with no login required, so anyone who can reach the port can run code on the server. CISA scored it CVSS 9.8. As of September 24, 2026, no fixed version has been released. Key facts: - Severity:CVSS 3.1 9.8 (CISA ADP); NVD not yet analysed(https://cveawg.mitre.org/api/cve/CVE-2026-93088) - CVE published:2026-09-22(https://cveawg.mitre.org/api/cve/CVE-2026-93088) - Fixed version:No fixed version yet (the CVE record lists no fixed version)(https://cveawg.mitre.org/api/cve/CVE-2026-93088) - Credited to:Keita Sode (SYZD Research)(https://cveawg.mitre.org/api/cve/CVE-2026-93088) - Weakness:CWE-502 Deserialization of Untrusted Data(https://cveawg.mitre.org/api/cve/CVE-2026-93088) Confirmed: - The DiffusionServer's ZeroMQ ROUTER socket has no authentication and calls pickle.loads() on received data before any checks. - As of the researcher's write-up, the latest release and main still contain the vulnerable code; there is no fixed version. - PlainCVE's source check on 2026-09-24: _handle_client_request() in v0.5.20 and that day's main still calls pickle.loads() directly. - Maintainer PR #40259 only changed srt/utils/common.py and did not touch the pickle.loads() in orchestrator.py. - The researcher published the core PoC snippet, the verification method and its output; CISA's SSVC in the CVE record rates Exploitation as poc. - Not in CISA KEV as of 2026-09-24 (catalog version 2026.09.23); not being listed does not mean it has not been exploited. Unconfirmed / disputed: - Whether the CVE record will update its affected range (currently 0.5.11 through 0.5.14), and when an official fixed version will be released. - The core PoC snippet and verification results have been published; whether a complete, ready-to-run tool also exists has not been verified. - Whether it has been exploited in the wild: no evidence either way; not being in KEV does not prove it hasn't been. 「Unpickling data from strangers is like letting a stranger's note tell your computer what to do.」— PlainCVE https://plaincve.date/en/vulns/cve-2026-93088-sglang-diffusion-pickle-rce
How to cite this page
This article is CC BY 4.0. Please keep the attribution and link when republishing.
PlainCVE Team (2026). "SGLang disaggregated diffusion pickle deserialization: anyone who can reach the ZeroMQ port can run code". PlainCVE. https://plaincve.date/en/vulns/cve-2026-93088-sglang-diffusion-pickle-rce (accessed YYYY-MM-DD)BibTeX
@misc{cve202693088sglangdiffusionpicklerce2026,
title = {SGLang disaggregated diffusion pickle deserialization: anyone who can reach the ZeroMQ port can run code},
author = {PlainCVE Team},
year = {2026},
howpublished = {PlainCVE},
url = {https://plaincve.date/en/vulns/cve-2026-93088-sglang-diffusion-pickle-rce},
note = {Updated 2026-09-28}
}