ray.data.read_webdataset(paths=...) is a @PublicAPI(stability="alpha")
reader for WebDataset-format TAR files. Its default decoder=True invokes
_default_decoder on every sample's keys, which routes file extension to a
decoder by extension. Two of those branches deserialize attacker-controlled
bytes with no validation:
.pickle / .pkl -> pickle.loads(value).pt / .pth -> torch.load(io.BytesIO(value), weights_only=False)Both fire during a standard ray.data.read_webdataset(...).take_all() /
.iter_batches() call. No flags, no opt-in, no environment variable.
An attacker who can supply a TAR (via S3 share, HuggingFace Hub mirror,
email attachment, model-zoo, or any HTTP URL the user passes to
read_webdataset) achieves arbitrary code execution in the calling
Ray process at schema-sample time, before row data is consumed.
This is the same class of bug as GHSA-mw35-8rx3-xf9r (Parquet Arrow
Extension Type cloudpickle deserialization, patched in 2.55.0): standard
data-loading API, attacker-controlled file format, deserialization gadget
invoked transparently. The 2.55.0 patch addressed
tensor_extensions/arrow.py:_deserialize_with_fallback and made cloudpickle
opt-in via RAY_DATA_AUTOLOAD_CLOUDPICKLE_TENSOR_METADATA=1. The
WebDataset path is a different code site and was not touched.
a157d4d)python/ray/data/_internal/datasource/webdataset_datasource.py lines
175-225, the _default_decoder function:
def _default_decoder(sample, format=True):
sample = dict(sample)
for key, value in sample.items():
extension = key.split(".")[-1]
...
elif extension in ["pt", "pth"]:
import torch
# PyTorch 2.6 changed torch.load default weights_only=True, which
# breaks loading general Python objects previously serialized for
# WebDataset .pt payloads.
sample[key] = torch.load(io.BytesIO(value),...
2.56.0Exploitability
AV:NAC:LAT:NPR:NUI:AVulnerable System
VC:HVI:HVA:HSubsequent System
SC:NSI:NSA:N8.6/CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N