GitHub Advisoryadvisory · PyPI

GHSA-6757-hggm-hp2w vLLM: Public multimodal SHM handle forgery reaches worker-side `pickle.loads()` with insecure serialization disabled

HIGH Published 2026-10-28 Modified 2026-10-28 Official page ↗
Aliases
CVE-2026-115912
Ecosystem
PyPI
Packages
vllm
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Weaknesses
CWE-502
Reviewed
2026-10-28

Affected packages

• PyPI vllm: < 0.32.0 → fixed in 0.32.0

Description

Affected • Ecosystem / package: pip / `vllm` • Affected versions: vLLM MultiModalKwargsItem: assert mm_item is not None, f"Expected an address item for {mm_hash=}" if "address" in mm_item: address = cast(int, mm_item["address"].data) monotonic_id = cast(int, mm_item["monotonic_id"].data) return self._shm_cache.get(address, monotonic_id) return mm_item ``` The dereference lands in the SHM deserializer, which `pickle.loads()` any chunk tagged as `bytes` — so attacker bytes staged in the ring buffer are unpickled in the worker process: ```python vllm/distributed/device_communicators/shm_object_storage.py Lines 375-400 def deserialize(self, data_view: memoryview) -> Any: # pickle.loads do not read past the end of a pickled object # within a large buffer, so we can skip storing the metadata size type_name, nbytes, len_arr = pickle.loads(data_view) serialized_data = data_view[-nbytes:] if type_name == torch.Tensor.__name__: obj = [] start_idx = 0 for length in len_arr: item_bytes = serialized_data[start_idx : start_idx + length] obj.append(item_bytes) start_idx += length obj = self.tensor_decoder.decode(obj) elif type_name == self._mm_kwargs_item_cls.__name__: obj = [] start_idx = 0 for length in len_arr: item_bytes = serialized_data[start_idx : start_idx + length] obj.append(item_bytes) start_idx += length obj = self.mm_decoder.decode(obj) elif type_name == bytes.__name__: obj = pickle.loads(serialized_data) else: raise ValueError(f"Unsupported object type '{type_name}' in metadata") return obj ``` Impact An ordinary authenticated inference caller can execute arbitrary Python in the worker process on a deployment that uses SHM multimodal caching. The live proof used a benign marker gadget and also caused the EngineCore health endpoint to fall from 200 to 503 after the forged request. The exploit is reachable with `VLLM_ALLOW_INSECURE_SERIALIZATION=0`; it abuses the built-in SHM object deserializer, not the separate optional msgpack ext-hook flag. Suggested Fix Authenticate every SHM carrier with a server-issued capability bound to the cache key, address, and monotonic id; rotate the capability secret when the cache is cleared; and reject malformed or forged SHM carriers at the public scale-out boundary before engine handoff — so a forged pair never reaches the worker deref / `pickle.loads()`. The sender emits an HMAC capability (keyed by a 32-byte secret stored in the ring buffer and rotated on `clear()`) over `(cache_key, address, monotonic_id)` alongside the pair. The public scale-out path validates it before engine handoff: ```python vllm/entrypoints/scale_out/token_in_token_out/serving.py cache = self.online_renderer.renderer.mm_processor_cache for mm_hash, item in zip(hashes, items): decoded_item = decode_mm_kwargs_item(item) if item is not None else None if decoded_item is not None and cache is not None: # Rejects a forged (address, monotonic_id) that lacks a valid # server-issued capability for this cache key. cache.validate_input_item(decoded_item, mm_hash) decoded_items.append(decoded_item) ``` The worker `get()` re-checks the capability on the reader side before it ever dereferences the caller-supplied address: ```python vllm/distributed/device_communicators/shm_object_storage.py def get(self, address, monotonic_id, capability=None, key=None): if not self.is_writer: # Reject forged handles before dereferencing the supplied address. self.validate_capability(key, address, monotonic_id, capability) with self.ring_buffer.access_buf(address) as (data_view, buf_metadata): self._validate_monotonic_id(address, monotonic_id, buf_metadata) obj = self.ser_de.deserialize(data_view[self.flag_bytes :]) ... ``` where `validate_capability` recomputes the HMAC with `hmac.compare_digest` and raises `Missing server-issued SHM capability for cache key.` / `Invalid server-issued SHM capability for cache key.` on any mismatch. The fix applies cleanly to `v0.25.1` and ships regression tests asserting the generate path rejects an invalid handle and that …

Related

Alias · CVE (1)

  • CVE-2026-115912 vLLM is an inference and serving engine for large language models. vulnerability

Weakness · CWE (1)

  • CWE-502 Deserialization of Untrusted Data weakness

References