Fix(security): block unsafe pickle deserialization to mitigate CVE-2025-10164 (#11909)
Co-authored-by: Chengxing Xie <xiechengxing34@gmail.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
f80371ff8c
commit
49afb3d9d9
@@ -98,3 +98,9 @@ Its core features include:
|
||||
references/custom_chat_template.md
|
||||
references/frontend/frontend_index.rst
|
||||
references/learn_more.md
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Security Acknowledgement
|
||||
|
||||
security/acknowledgements.md
|
||||
|
||||
3
docs/security/acknowledgements.md
Normal file
3
docs/security/acknowledgements.md
Normal file
@@ -0,0 +1,3 @@
|
||||
| Time | CVE ID | Credit to | Affected Versions | Severity | Impact | Description |
|
||||
|------------|--------------|------------------|---------------------------|------------|----------------------|-------------|
|
||||
| 2025-09-09 | CVE-2025-10164 | Simon Huang, pjf | ≥ 0.4.6 & ≤ 0.5.3 | Critical | Remote Code Execution | A security flaw exists in lmsys sglang versions ≥ 0.4.6 and ≤ 0.5.3. The vulnerability arises from the use of unsafe pickle deserialization of the `serialized_named_tensors` parameter in the `/update_weights_from_tensor` API endpoint, which could allow a remote attacker to execute arbitrary code on the server by sending a specially crafted payload. |
|
||||
@@ -2099,7 +2099,78 @@ class MultiprocessingSerializer:
|
||||
# Decode base64 string to bytes
|
||||
data = pybase64.b64decode(data, validate=True)
|
||||
|
||||
return ForkingPickler.loads(data)
|
||||
class SafeUnpickler(pickle.Unpickler):
|
||||
ALLOWED_MODULE_PREFIXES = {
|
||||
# --- Python types ---
|
||||
"builtins.",
|
||||
"collections.",
|
||||
"copyreg.",
|
||||
"functools.",
|
||||
"itertools.",
|
||||
"operator.",
|
||||
"types.",
|
||||
"weakref.",
|
||||
# --- PyTorch types ---
|
||||
"torch.",
|
||||
"torch._tensor.",
|
||||
"torch.storage.",
|
||||
"torch.nn.parameter.",
|
||||
"torch.autograd.function.",
|
||||
# --- torch distributed ---
|
||||
"torch.distributed.",
|
||||
"torch.distributed._shard.",
|
||||
"torch.distributed._composable.",
|
||||
"torch._C._distributed_c10d.",
|
||||
"torch._C._distributed_fsdp.",
|
||||
"torch.distributed.optim.",
|
||||
# --- multiprocessing ---
|
||||
"multiprocessing.resource_sharer.",
|
||||
"multiprocessing.reduction.",
|
||||
"pickletools.",
|
||||
# --- PEFT / LoRA ---
|
||||
"peft.",
|
||||
"transformers.",
|
||||
"huggingface_hub.",
|
||||
# --- SGLang & Unitest ---
|
||||
"sglang.srt.weight_sync.tensor_bucket.",
|
||||
"sglang.srt.model_executor.model_runner.",
|
||||
"sglang.srt.layers.",
|
||||
"sglang.srt.utils.",
|
||||
}
|
||||
|
||||
DENY_CLASSES = {
|
||||
("builtins", "eval"),
|
||||
("builtins", "exec"),
|
||||
("builtins", "compile"),
|
||||
("os", "system"),
|
||||
("subprocess", "Popen"),
|
||||
("subprocess", "run"),
|
||||
("codecs", "decode"),
|
||||
("types", "CodeType"),
|
||||
("types", "FunctionType"),
|
||||
}
|
||||
|
||||
def find_class(self, module, name):
|
||||
# Block deterministic attacks
|
||||
if (module, name) in self.DENY_CLASSES:
|
||||
raise RuntimeError(
|
||||
f"Blocked unsafe class loading ({module}.{name}), "
|
||||
f"to prevent exploitation of CVE-2025-10164"
|
||||
)
|
||||
# Allowlist of safe-to-load modules.
|
||||
if any(
|
||||
(module + ".").startswith(prefix)
|
||||
for prefix in self.ALLOWED_MODULE_PREFIXES
|
||||
):
|
||||
return super().find_class(module, name)
|
||||
|
||||
# Block everything else. (Potential attack surface)
|
||||
raise RuntimeError(
|
||||
f"Blocked unsafe class loading ({module}.{name}), "
|
||||
f"to prevent exploitation of CVE-2025-10164"
|
||||
)
|
||||
|
||||
return SafeUnpickler(io.BytesIO(data)).load()
|
||||
|
||||
|
||||
def debug_timing(func):
|
||||
|
||||
Reference in New Issue
Block a user