LightLLM through 1.2.0 runs an unauthenticated, pickle-enabled RPyC service on visual_only nodes. Anyone who can reach the port can run code, and no fix exists yet.
A critical flaw in LightLLM, ModelTC's open-source LLM inference server, allows anyone who can reach the visual RPyC port of a visual_only multimodal node to execute arbitrary code. The CVE record covers LightLLM through 1.2.0. As of 3 October 2026 no fixed release exists, and the upstream issue is open with no comments. CVE-2026-103395 carries CVSS 9.8 (v3.1) and 9.3 (v4.0), both assigned by VulnCheck, the CNA. We found no report of exploitation, and it is not in CISA's KEV catalog.
What happened
VulnCheck published CVE-2026-103395 on 30 September 2026. The record says LightLLM through 1.2.0 visual_only deployments "expose an unauthenticated RPyC service with allow_pickle enabled that deserializes attacker-supplied arguments in the remote_infer_images method," and that attackers can reach the port and pass objects with __reduce__ methods to run code with service account privileges. The record credits Mingkai Yu and Jiajia Liu as finders. The matching public report, issue #1610, was opened the same morning. NVD lists the entry as Deferred and has not scored it. The CVSS figures are VulnCheck's.
Why it matters
LightLLM is used to serve large models, and multimodal setups can split image preprocessing onto dedicated visual nodes. Those nodes often sit close to GPU hosts and internal networks. A flaw that needs no credentials and no user interaction gives an attacker the service account's privileges. The issue reporter says that account belonged to the sudo and docker groups in their test environment; that is specific to their setup and not a general finding.
This is the third unauthenticated RPyC pickle-RCE CVE in LightLLM published on 29–30 September, and the sixth unauthenticated deserialization RCE in LightLLM this year (CVE-2026-26220, -90919, -96560, -103040, -103041 and -103395), all affecting 1.2.0 or earlier and all Deferred in NVD. CVE-2026-103040 (router profiler service) and CVE-2026-103041 (multimodal embed-cache service) were published on 29 September. The reporter of #1610 states this one is a different mode, process, port and method, so fixing those two would not fix it. CVE-2026-90919 (14 September) covers the Config Server's unauthenticated /visual_register WebSocket, which passes the first client frame to pickle.loads(), a separate exposure in visual deployments. CVE-2026-96560 (23 September) covers the KV-transfer worker's unauthenticated RPyC control channel when started with --pd_trans_mode nccl; the same channel also has a memory-exhaustion flaw, CVE-2026-103042 (29 September). The earliest, CVE-2026-26220 (LightLLM 1.1.0 and prior), covered unauthenticated pickle.loads on the prefill-decode master's WebSocket endpoints; upstream issue #1213 for it is still open. CISA's ADP entry rates CVE-2026-103395 as exploitation "poc", automatable "yes", technical impact "total". For another serving stack with open flaws and no fixed release named, see our coverage of the vLLM NIXL and Mooncake connector bugs.
Technical details
How CVE-2026-103395 reaches code execution on a LightLLM visual_only node. Until a fix ships, firewalling or segmenting the visual RPyC port is the control point.
All paths are at tag v1.2.0 unless noted.
lightllm/server/visualserver/objs.py(lines 6-11) definesrpyc_configwithallow_pickle,allow_all_attrs,allow_getattrandallow_setattrallTrue.lightllm/server/visualserver/visual_only_manager.pydefinesexposed_remote_infer_images(line 138), which callsobtain(images)(line 140) on the caller's argument. With pickling allowed, a client object that cannot be passed by reference is unpickled on the server, so a crafted object runs code before the method's later type handling fails.- The same file starts
rpyc.ThreadedServer(visualserver, port=get_shm_port_args().visual_rpyc_port, protocol_config=rpyc_config)(line 203) with nohostnameargument and no authenticator. In rpyc 5.3.1, aNonehostname is resolved as a passive wildcard address, so the server listens on0.0.0.0, every IPv4 interface. The reporter's socket listing in #1610 shows the same. We read both code bases but did not run the service. - The mode is selected with
--run_mode visual_only. The port comes from--visual_rpyc_port, whose default inlightllm/server/api_cli.pyisNone; the reporter says a dynamic port is then allocated. The reporter also says startup requires--config_server_visual_redis_port. - The weakness is CWE-502 per the CVE record. The reporter additionally cites CWE-306 (missing authentication).
The reporter says they reproduced code execution locally and from a second host at commit 1eb4810c (v1.2.0+50) with rpyc 5.3.1, and that main matched as of 30 September. A proof of concept is in the issue; we link it and do not reproduce it here.
What defenders should do
- Find LightLLM nodes started with
--run_mode visual_only. Standard single-nodenormaldeployments are not described as affected by this CVE. Two other exposures are separate from this one: a config_server node (CVE-2026-90919, on the Config Server port) and workers started with--pd_trans_mode nccl(CVE-2026-96560 and CVE-2026-103042, on the KV-transfer RPyC port). The same firewall and segmentation advice below applies to those ports. - Do not expose the visual RPyC port to untrusted networks. Block it at host and network firewalls, allowing only the specific LightLLM nodes that must call it.
- Place visual nodes in a segmented network or private VLAN with no inbound path from the internet or general user networks.
- Run the service as an unprivileged account with no
sudoordockergroup membership, and limit its outbound access and credentials. - Watch for unexpected connections to the visual RPyC port and for child processes spawned by the LightLLM visual server process.
- Subscribe to issue #1610 and the LightLLM releases page, and upgrade once a fixed version is named. We found no flag to bind the port to localhost or a private interface; the
ThreadedServercall takes no host from the CLI, so the interim control is a firewall rule or a local code change. Treat any local patch as unvetted.
What is still unclear
- Whether and when ModelTC will ship a fix. As of 3 October 2026 there is no release after v1.2.0 (10 August 2026), no commit addressing this on main (HEAD
6c9e03b1, 29 September), and no pull request referencing the issue. Several other pickle-related security PRs in the repository have been open for weeks or months. - Whether exploitation has occurred. Nothing we found reports it.
- The exact default or allocated port range, which we did not verify.
- NVD's own severity assessment, since the entry is Deferred.
Sources
- NVD record and NVD API
- CVE.org record
- VulnCheck advisory
- LightLLM issue #1610
- rpyc 5.3.1 server.py (bind logic)
- objs.py at v1.2.0
- visual_only_manager.py at v1.2.0
- LightLLM api_cli.py (main)
- CISA KEV JSON
- NVD records for CVE-2026-103040, CVE-2026-103041, CVE-2026-26220, CVE-2026-90919, CVE-2026-96560 and CVE-2026-103042