
LMCache CVE-2026-105192: RCE 9.8 Belum Ditampal
LMCache CVE-2026-105192: RCE 9.8 Belum Ditampal
Pada 7 Oktober 2026, JFrog menerbitkan satu kelemahan dalam LMCache yang sukar dipandang ringan: remote code execution tanpa authentication, CVSS 9.8, dan tiada release yang sudah ditampal untuk dipasang. Rekod CVE dengan nombor yang sama, diterbitkan pada hari yang sama, membawa skor yang sama serta lajur patch yang kosong.
LMCache ialah lapisan KV-cache yang dipasang atas vLLM supaya prefix yang sama tidak dikira semula pada setiap request. Ia software infrastruktur, bermakna ia cenderung berjalan senyap di atas sesuatu kotak GPU dan disentuh hanya apabila throughput turun. Itulah profil komponen yang tiada sesiapa perhatikan sehinggalah ada scanner melakukannya.
Bug itu sendiri bukanlah sesuatu yang mengejutkan bagi siapa pun yang pernah melihat Python menghantar data merentas socket. Yang menarik ialah bentuk pendedahan anda: keseluruhan skor CVSS datang daripada satu command-line flag, dan manifest contoh projek itu sendirilah yang menetapkan flag itu.
Apa yang sebenarnya rosak
LMCache mempunyai mode multiprocess, juga dipanggil mode distributed, di mana cache berjalan sebagai server berdiri sendiri yang dicapai oleh worker process melalui ZeroMQ. Server itu membuka sebuah ROUTER socket supaya peer boleh mendaftar dan berkongsi block KV cache. Tiada CURVE, tiada ZAP, tiada password, dan tiada message-level authentication ke atasnya. Client yang dimaksudkan ialah process LMCache lain dalam kumpulan yang sama, dan tiada apa pun pada wire mengesahkan bahawa ia benar-benar salah seorang daripada mereka.
Mesej pada socket itu dalam format msgpack. Extension code 1 didaftarkan
untuk DeviceIPCWrapper, dan ia dihantar kepada
DeviceIPCWrapper.Deserialize,
yang memanggil pickle.loads. pickle dengan senang hati membina semula objek
yang menjalankan kod semasa ia decode — itu memang reka bentuk format itu.
Yang menjadikannya boleh dieksploitasi dan bukan sekadar buruk ialah bila
proses unpickling berlaku. Hook itu dicetuskan daripada ext_hook di dalam
custom_types.py
semasa server masih lagi decode argument bagi mesej REGISTER_KV_CACHE —
sebelum handler berjalan, sebelum server sempat memeriksa jenis mesej apa yang
diterimanya langsung. Satu frame DEALER tanpa authentication ke port transport
(lalai 5555) menjalankan kod penghantar semasa decode juga.
Handler itu kemudian gagal, kerana ia menjangka DeviceIPCWrapper tetapi
menerima nilai pulangan daripada os.system. Error itu direkod selepas
commandnya sudahpun berjalan. Kod berjalan dengan privilege milik process
LMCache, dan pada image container rasmi projek itu process itu berjalan
sebagai root, menurut advisory JFrog.
JFrog mengkreditkan Yuval Moravchick daripada pasukan security research mereka
dengan penemuan ini. Rekod CVE mengklasifikasikannya sebagai
CWE-502, deserialization of untrusted data,
digandingkan dengan CWE-306, missing authentication for a critical function —
pasangan yang anda jangka daripada sebuah serializer dan sebuah socket
yang tidak pernah dimaksudkan untuk menghadap sesiapa.
Perlu dinyatakan dengan jelas: satu salinan LMCache yang berjalan dalam satu process vLLM tidak membuka port ini langsung. Ini ialah bug mode distributed.
Skor CVSS anda ialah satu command-line flag
Secara lalai, server multiprocess itu berbind ke localhost, jadi host lain tidak boleh mencapainya. Ia menjadi boleh dicapai apabila operator memulakannya dengan address yang routable — dan itulah tepat-tepatnya cara deployment multi-node berkongsi satu cache merentas mesin. Itulah seluruh jarak antara "tidak terdedah" dan 9.8.
Medan scenario pada entri CVSS JFrog menyatakannya dan bukannya menyembunyikannya: "Multiprocess mode bound to a routable address, the documented multi-node deployment." Skor itu bukan untuk salah konfigurasi. Ia untuk mengikut dokumentasi.
Dan contoh dalam dokumentasi itu sendiri bersetuju. Manifest contoh Kubernetes LMCache memulakan server yang berbind pada setiap network interface:
# The documented multi-node setting — and the vulnerable one.
python -m lmcache.v1.multiprocess.http_server \
--http-host 127.0.0.1 --http-port 8080 \
--host 0.0.0.0 --port 5555 \
--l1-size-gb 0.25 --eviction-policy LRU \
--hash-algorithm blake3 --instance-id mp-node-01
--host 0.0.0.0 ialah baris yang penting. Kekalkan transport pada localhost dan
penyerang remote tiada sasaran untuk menghantar frame. Letakkan ia di belakang
firewall dan anda sudah mengurangkan siapa yang boleh mencapai port itu, tetapi
anda tidak membuang masalahnya — JFrog menyatakan dengan eksplisit bahawa
mana-mana host yang masih boleh membuka sambungan ke port itu masih boleh
menjalankan kod sebagai user LMCache anda.
Tiada apa-apa untuk dinaik taraf
Inilah bahagian yang menjadikannya lebih teruk daripada advisory patch biasa.
- Terjejas: 0.3.9 (direlease Oktober 2025) sehingga 0.5.5, stable terkini
di PyPI, ditambah release candidate
0.5.6sehingga0.5.6rc3serta development branch pada 7 Oktober 2026. - Dibaiki: tiada. Path decode itu masih wujud dalam release terkini.
- Advisory vendor: tiada. Halaman security advisory GitHub LMCache kosong.
Jadi tiada nombor version untuk disasarkan, yang juga bermakna tiada cara
bersih untuk menjawab "adakah kami sudah ditampal?". Mitigation yang pragmatik
ialah konfigurasi dan bukan patch: jangan tetapkan --host kepada address yang
routable, kekalkan port multiprocess pada localhost atau pada trusted cluster
network, dan jika anda benar-benar perlukan multi-node, anggap bahawa setiap
mesin yang boleh mencapai port itu ialah mesin yang boleh execute kod sebagai
user LMCache anda.
Fix yang digambarkan JFrog untuk reka bentuk asasnya ialah fix yang anda akan
tulis sendiri: berhenti menyerahkan network bytes kepada pickle, gantikan
serializer di belakang extension code 1 dengan sesuatu yang tidak boleh
membawa kod, authenticate transport ZMQ — CURVE, atau HMAC ke atas setiap
mesej — dan jangan berbind kepada address yang routable kecuali
authentication itu sudah dikonfigurasikan.
Satu jurang yang perlu dinamakan: advisory itu tidak memberi operator apa-apa cara untuk menentukan sama ada server itu sudah diserang. Tiada indicator of compromise di dalamnya.
Semak pendedahan anda sebelum buka ticket
Script di bawah ialah semakan statik: ia membaca LMCache yang dipasang, mencari
call pickle.loads, dan membaca jadual listener TCP tempatan untuk melihat
sama ada port transport berbind pada address routable. Ia tidak menghantar
apa-apa, jadi selamat dijalankan pada production. Exit code 1 bermakna
terdedah, 0 bermakna tiada yang dijumpai, dan 2 bermakna ia tidak boleh
memberitahu.
#!/usr/bin/env python3
"""Static exposure check for CVE-2026-105192 (LMCache pickle RCE).
Run it with the same interpreter that runs your LMCache or vLLM stack.
It never touches the network - it only reads the local install and the
local TCP listener table, and answers three questions:
1. Is the installed LMCache in the affected range (>= 0.3.9)?
2. Does the installed code still hand socket bytes to pickle.loads?
3. Is the multiprocess ZMQ transport listening on a routable address?
Exit codes: 0 = no exposure found, 1 = exposure found, 2 = cannot tell.
"""
import re
import socket
import sys
from importlib import metadata
from pathlib import Path
AFFECTED_SINCE = (0, 3, 9)
TRANSPORT_PORT = 5555 # LMCache multiprocess ZMQ default
LOOPBACK = {"127.0.0.1", "::1"}
def parse_version(text):
m = re.match(r"(\d+)\.(\d+)\.(\d+)", text or "")
return tuple(int(g) for g in m.groups()) if m else None
def installed_version():
try:
return metadata.version("lmcache")
except metadata.PackageNotFoundError:
return None
def pickle_source_path():
try:
import lmcache
root = Path(lmcache.__file__).resolve().parent
except Exception:
return None
path = root / "v1" / "platform" / "base" / "ipc_wrapper.py"
return path if path.is_file() else None
def listening_sockets(proc_net=None):
"""Return (port, addr) for every TCP listener. Linux /proc only."""
base = Path(proc_net) if proc_net else Path("/proc/net")
found = []
for name in ("tcp", "tcp6"):
try:
lines = (base / name).read_text().splitlines()[1:]
except OSError:
continue
for line in lines:
parts = line.split()
if len(parts) < 4 or parts[3] != "0A": # 0A = TCP_LISTEN
continue
addr_hex, port_hex = parts[1].split(":")
port = int(port_hex, 16)
if name == "tcp6":
raw = bytes.fromhex(addr_hex)
# the kernel stores each 32-bit word little-endian
raw = b"".join(raw[i:i + 4][::-1] for i in range(0, 16, 4))
addr = socket.inet_ntop(socket.AF_INET6, raw)
else:
addr = socket.inet_ntoa(bytes.fromhex(addr_hex)[::-1])
found.append((port, addr))
return found
def is_routable(addr):
if addr in ("0.0.0.0", "::", "::0"):
return True
if addr in LOOPBACK:
return False
return not addr.startswith("fe80")
def main():
findings = []
exit_code = 0
version = installed_version()
if version is None:
findings.append("? lmcache is not importable here - run me with the "
"interpreter that has it installed.")
exit_code = 2
else:
parsed = parse_version(version)
if parsed and parsed >= AFFECTED_SINCE:
findings.append(f"[!] LMCache {version} is in the affected range "
"(>= 0.3.9); no fixed release exists as of "
"2026-10-07.")
exit_code = 1
else:
findings.append(f"[ok] LMCache {version} predates the vulnerable "
"code path (introduced in 0.3.9).")
src = pickle_source_path()
if src is None:
findings.append("? could not locate ipc_wrapper.py to inspect.")
exit_code = max(exit_code, 2)
elif "pickle.loads" in src.read_text(errors="ignore"):
findings.append(f"[!] {src} still calls pickle.loads on socket data.")
exit_code = max(exit_code, 1)
else:
findings.append(f"[ok] {src} no longer unpickles socket data.")
open_ports = {}
for port, addr in listening_sockets():
open_ports.setdefault(port, set()).add(addr)
addrs = open_ports.get(TRANSPORT_PORT)
if not addrs:
findings.append(f"[ok] nothing is listening on port {TRANSPORT_PORT} "
"on this host.")
elif any(is_routable(a) for a in addrs):
bad = sorted(a for a in addrs if is_routable(a))
findings.append(f"[!] ZMQ transport port {TRANSPORT_PORT} is bound to "
f"routable address {', '.join(bad)} - reachable "
"from other machines.")
exit_code = max(exit_code, 1)
else:
findings.append(f"[ok] port {TRANSPORT_PORT} is bound to loopback "
"only ({}).".format(", ".join(sorted(addrs))))
print("CVE-2026-105192 exposure check")
for line in findings:
print(" " + line)
print("=> " + ("EXPOSED" if exit_code == 1 else
"cannot tell" if exit_code == 2 else "no exposure found"))
return exit_code
if __name__ == "__main__":
sys.exit(main())
Enam lagi laporan, satu pengadu
Sehari sebelum CVE itu menjadi awam, satu akaun GitHub mengemukakan enam lagi
laporan security LMCache dalam masa kurang empat jam: baca dan tulis KV cache
rentas tenant tanpa authentication,
fleet control plane tanpa authentication pada 0.0.0.0:9300,
satu flaw allocation hold dan key injection dalam PD transfer backend, satu
sandbox escape run_script,
control plane cache tanpa authentication serta disclosure environment,
dan poisoning katalog proxy.
Anggap kesemua enam itu dengan berhati-hati. Semuanya datang daripada satu akaun,
bergantung pada claim proof-of-concept, dan tiada CVE, tiada pengesahan daripada
maintainer serta tiada fix — balasan setakat ini hanyalah pengguna lain
menawarkan diri untuk mengambil kerja itu. Salah satunya menunjuk kepada satu
default yang sudahpun bergerak: server HTTP multiprocess yang berbind pada
0.0.0.0:8080 dalam 0.5.5 berbind pada 127.0.0.1 dalam release candidate
0.5.6. Kesemua isu itu masih terbuka pada penulisan ini. Melaporkannya adalah
wajar; memperlakukannya sebagai bug yang disahkan ialah satu dakwaan yang
berbeza daripada bukti yang ada.
Bersebelahan, bukan bug yang sama
Jangan kelirukan ini dengan CVE-2026-105756,
denial-of-service vLLM yang sudah dibaiki dalam vLLM 0.30.0, direlease
22 September 2026. Yang itu ialah nilai cache_salt tidak sah yang menjatuhkan
engine pada deployment yang menggunakan LMCache multiprocess connector, dinilai
6.5, dan tanpa code execution. Ia sudah dibaiki. CVE-2026-105192 belum.
Pola yang sama
Menyerahkan data daripada socket network tanpa authentication kepada pickle
bukanlah satu kesilapan baru. Penyelidik mendokumenkan kelemahan teras yang sama
merentas sekumpulan AI inference framework pada November 2025 dan memanggil
kumpulan itu ShadowMQ.
Sama ada kod LMCache berkongsi source biasa dengan projek-projek itu belum dapat
ditetapkan, dan memang janggal untuk menyarankan sebaliknya.
Yang pasti ialah inference stack terus mempelajari semula pelajaran yang sama: sebuah service account dalaman, satu port yang kelihatan reachable dalam contoh yang disalin orang, dan satu format serialisasi yang execute kod. Rantaian JFrog Artifactory yang kami lipat pada September adalah bug berbeza dengan bentuk berbeza, tetapi soalannya sama: apa yang sebenarnya listening, dan siapa boleh mencapainya. Ia soalan yang sama yang sentiasa gagal dijawab oleh deployment MCP, satu registry awam pada satu masa.
Apa yang perlu dilakukan hari ini
- Kenal pasti sama ada anda menjalankan LMCache dalam mode multiprocess. Jika cache anda berjalan dalam satu process vLLM, port ini memang tidak wujud untuk anda.
- Jika ya, semak bind address sebelum apa-apa lagi. Bind ke loopback sahaja
tidak boleh dieksploitasi dari luar;
0.0.0.0boleh. - Jika anda perlukan multi-node, letakkan transport pada trusted cluster network dan hadkan ia dengan firewall, kemudian anggap bahawa setiap host pada network itu boleh execute kod sebagai user LMCache anda — kerana memang boleh.
- Jangan tunggu patch yang dijadualkan. Tiada tarikh diterbitkan, dan vendor belum mengeluarkan advisory.
- Baca advisory JFrog sendiri — ia membawa proof of concept yang berfungsi serta senarai mitigation penuh.
RCE 9.8 yang belum ditampal pada komponen yang wujud untuk menjadikan inference lebih murah bukanlah satu penemuan niche. Fix itu kelak ialah pertukaran serializer dan sebuah socket yang authenticated. Sehingga ia tiba, security boundary anda seluas satu flag, dan config contoh berada di sebelah yang salah.
Sumber
- JFrog Security Research: LMCache is vulnerable to Unauthenticated Remote Code Execution via Pickle Deserialization on the Multiprocess ZMQ Transport
- CVE Program: CVE-2026-105192
- The Hacker News: Unpatched Critical LMCache Flaw Lets Unauthenticated Attackers Run Code Remotely
- vLLM Project: GHSA-2823-qmq8-rwvj: vLLM cache_salt denial of service
- LMCache (GitHub): Unauthenticated cross-tenant KV cache read, write, and unbounded storage on LMCache server
// penulis
Editor & Operator
Mohd Firdaus Abu Bakar (MrDodgerX) is an enterprise geospatial systems engineer in Malaysia and the editor behind hejes.my. He runs the briefing pipeline, curates and edits every draft, verifies each factual claim against primary sources, and presses the publish button — nothing ships without his review. He writes about AI, security and Malaysia's tech scene from a builder's perspective. Professional profile and code: the links below.
// sumber //
disahkan fakta · 08 OKT 2026 · hejes-content-fact-check
- LMCache is vulnerable to Unauthenticated Remote Code Execution via Pickle Deserialization on the Multiprocess ZMQ TransportJFrog Security Research · diakses 08 OKT 2026
- CVE-2026-105192CVE Program · diakses 08 OKT 2026
- Unpatched Critical LMCache Flaw Lets Unauthenticated Attackers Run Code RemotelyThe Hacker News · diakses 08 OKT 2026
- GHSA-2823-qmq8-rwvj: vLLM cache_salt denial of servicevLLM Project · diakses 08 OKT 2026
- Unauthenticated cross-tenant KV cache read, write, and unbounded storage on LMCache serverLMCache (GitHub) · diakses 08 OKT 2026
berkaitan //

FortiMail Zero-Day: Matikan IBE, Cari Jejak
Flaw path traversal 9.8 bersama NULL byte dalam FortiMail sedang dieksploitasi. Workaround-nya tiga baris CLI, tapi tidak membantu kotak yang sudah kena.

CEO Flock kata hanya tembakan, laman web kata lain
CEO Flock kata sensor audio mereka mengesan "hanya tembakan", tetapi halaman produk dan FAQ syarikat menyenaraikan kemalangan, bunga api dan sideshow juga.

Anthropic dapati bahan asas untuk AI worm masa depan
Kajian Anthropic menunjukkan model open-weight kecil boleh menyusun langkah replikasi kendiri, tetapi had hardware dan lebar jalur masih menyukarkannya.
// sertai suapan
satu ilmu seminggu. tiada spam.
ringkasan mingguan. berhenti bila-bila masa.