Restrict SafeUnpickler standard-library globals (#39858)

Co-authored-by: jiayisuse <jiayisuse@fb.com>
This commit is contained in:
Lianmin Zheng
2026-09-17 01:09:55 -07:00
committed by GitHub
co-authored by jiayisuse
parent 71ef869ece
commit 882577451e
2 changed files with 105 additions and 36 deletions
+33 -36
View File
@@ -2967,16 +2967,38 @@ def normalize_serialized_named_tensor_payloads(
class SafeUnpickler(pickle.Unpickler):
ALLOWED_MODULE_PREFIXES = {
# Standard-library modules expose powerful callables alongside harmless data
# types. Keep these globals exact so a newly added callable is denied by
# default instead of silently expanding the unpickling attack surface.
ALLOWED_GLOBALS = {
# --- Python types ---
"builtins.",
"collections.",
"copyreg.",
"functools.",
"itertools.",
"operator.",
"types.",
"weakref.",
("builtins", "bool"),
("builtins", "bytearray"),
("builtins", "bytes"),
("builtins", "complex"),
("builtins", "dict"),
("builtins", "float"),
("builtins", "frozenset"),
("builtins", "int"),
("builtins", "list"),
("builtins", "range"),
("builtins", "set"),
("builtins", "slice"),
("builtins", "str"),
("builtins", "tuple"),
("collections", "OrderedDict"),
("collections", "defaultdict"),
("collections", "deque"),
("functools", "partial"),
("itertools", "chain"),
("itertools", "repeat"),
("multiprocessing.reduction", "_rebuild_partial"),
("multiprocessing.reduction", "_rebuild_socket"),
("multiprocessing.resource_sharer", "DupFd"),
("types", "SimpleNamespace"),
}
ALLOWED_MODULE_PREFIXES = {
# --- PyTorch types ---
"torch.",
"torch._tensor.",
@@ -2990,10 +3012,6 @@ class SafeUnpickler(pickle.Unpickler):
"torch._C._distributed_c10d.",
"torch._C._distributed_fsdp.",
"torch.distributed.optim.",
# --- multiprocessing ---
"multiprocessing.resource_sharer.",
"multiprocessing.reduction.",
"pickletools.",
# --- PEFT / LoRA ---
"peft.",
"transformers.",
@@ -3009,35 +3027,14 @@ class SafeUnpickler(pickle.Unpickler):
"torch_npu.",
}
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(
if (module, name) in self.ALLOWED_GLOBALS or 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"
f"Blocked unsafe global ({module}.{name}) during pickle deserialization"
)