Skip to content

Commit 5fc5c18

Browse files
authored
fix(security): replace unsafe pickle.loads with SafeUnpickler for CVE-2026-3989 (#20904)
1 parent 8d4fca5 commit 5fc5c18

3 files changed

Lines changed: 9 additions & 2 deletions

File tree

docs/developer_guide/contribution_guide.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ Users listed in [CI_PERMISSIONS.json](https://github.com/sgl-project/sglang/blob
166166
- If a single test file run longer than 500 seconds, split it into multiple smaller files (e.g., `test_eagle_infer_a.py`, `test_eagle_infer_b.py`).
167167
- If a single job in a github workflow runs longer than 30 mins, split it into smaller jobs/steps.
168168
- Reuse server launches in your unit tests to make tests run faster.
169+
- Never use `pickle.loads()`, `pickle.load()`, or `recv_pyobj()` to deserialize untrusted or network-received data. Python's [pickle module is not secure](https://docs.python.org/3/library/pickle.html) — it can execute arbitrary code during deserialization. Use safe serialization formats such as [msgpack](https://github.com/jcrist/msgspec) or JSON instead.
169170
- When supporting new hardware or features, follow these guidelines:
170171
- Do not drastically change existing code.
171172
- Always prefer new files to introduce specific components for your new hardware (e.g., `allocator_ascend.py`).

python/sglang/srt/utils/common.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2144,6 +2144,11 @@ def find_class(self, module, name):
21442144
)
21452145

21462146

2147+
def safe_pickle_load(fp):
2148+
"""Drop-in replacement for pickle.load() that blocks unsafe class loading."""
2149+
return SafeUnpickler(fp).load()
2150+
2151+
21472152
def debug_timing(func):
21482153
# todo: replace with a more organized instrumentation
21492154
def wrapper(*args, **kwargs):

scripts/playground/replay_request_dump.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import argparse
1111
import glob
1212
import json
13-
import pickle
1413
import time
1514
from concurrent.futures import ThreadPoolExecutor
1615
from dataclasses import asdict
@@ -19,6 +18,7 @@
1918
import requests
2019

2120
from sglang.benchmark.utils import set_ulimit
21+
from sglang.srt.utils.common import safe_pickle_load
2222
from sglang.utils import get_exception_traceback
2323

2424

@@ -54,7 +54,8 @@ def normalize_request_data(json_data):
5454
def read_records(files):
5555
records = []
5656
for f in files:
57-
tmp = pickle.load(open(f, "rb"))
57+
with open(f, "rb") as fh:
58+
tmp = safe_pickle_load(fh)
5859
if isinstance(tmp, dict) and "requests" in tmp:
5960
records.extend(tmp["requests"])
6061
else:

0 commit comments

Comments
 (0)