GitHub Advisoryadvisory · PyPI
GHSA-6757-hggm-hp2w vLLM: Public multimodal SHM handle forgery reaches worker-side `pickle.loads()` with insecure serialization disabled
HIGH
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
- https://github.com/vllm-project/vllm/security/advisories/GHSA-6757-hggm-hp2w web
- https://nvd.nist.gov/vuln/detail/CVE-2026-115912 advisory
- https://github.com/vllm-project/vllm/pull/59357 web
- https://github.com/vllm-project/vllm/commit/3d5625cc3c2474994107047d7a6ecb8e4008f9b0 web
- https://github.com/vllm-project/vllm package
- https://github.com/vllm-project/vllm/releases/tag/v0.32.0 web