SGLang is a widely-used open-source framework for serving large language models and multimodal AI models.

Antiproof identified three vulnerabilities in SGLang that allow an unauthenticated attacker to achieve remote code execution on the host running SGLang. We responsibly disclosed the vulnerabilities to the vendor and subsequently coordinated disclosure with CERT/CC (case VU#777338). As of publication, no official patch is available, and the vendor did not respond during coordination.

Assigned CVEs

CVETypeCVSS 3.1Affected versionsPreconditions
CVE-2026-7301 Remote code execution 9.8 v0.5.5 and later Multimodal runtime enabled, scheduler socket reachable (--host 0.0.0.0)
CVE-2026-7302 Arbitrary file write 9.1 v0.5.5 and later Multimodal runtime enabled, HTTP API reachable
CVE-2026-7304 Remote code execution 9.8 v0.4.1.post7 and later --enable-custom-logit-processor set, generation endpoint reachable

CVSS 3.1 scores are Antiproof's assessment. The --enable-custom-logit-processor flag is off by default but recommended by SGLang's documentation for serving DeepSeek-R1 and GLM-4.

Background on pickle deserialization

Two of the three vulnerabilities involve unsafe deserialization, a vulnerability class explicitly warned against in Python's documentation. A crafted serialized payload can achieve remote code execution when deserialized by pickle.loads() or dill.loads():

class RCE:
    def __reduce__(self):
        return (os.system, ("id",))

CVE-2026-7301Remote code execution on the scheduler socket Critical CVSS 3.1 9.8

The multimodal generation runtime's scheduler binds a ZeroMQ ROUTER socket on the configured --host. Although the code default is 127.0.0.1, SGLang's official installation guide uses --host 0.0.0.0 in every serving example (Docker, SkyPilot, AWS SageMaker), and the official Docker Compose configuration deploys with network_mode: host, meaning the socket is exposed on all network interfaces in standard deployments.

An unauthenticated attacker can send a malicious pickle that reaches the scheduler's pickle.loads() call:

scheduler.py:272-276
parts = self.receiver.recv_multipart(zmq.NOBLOCK)
identity, payload = parts[0], parts[-1]

recv_reqs = pickle.loads(payload) if len(parts) > 2 else []

This vulnerability is distinct from CVE-2026-3059, the ZeroMQ broker described below. The broker binds to all interfaces unconditionally regardless of --host, while the scheduler ROUTER socket is reachable only when --host 0.0.0.0 is set.

CVE-2026-7302Arbitrary file write via path traversal Critical CVSS 3.1 9.1

The multimodal generation runtime accepts file uploads on its OpenAI-compatible image and video editing endpoints, /v1/images/edits and /v1/videos. Both endpoints route uploads through a shared helper, _save_upload_to_path, which writes to the path it receives:

utils.py:125-130
async def _save_upload_to_path(upload: UploadFile, target_path: str) -> str:
    os.makedirs(os.path.dirname(target_path), exist_ok=True)
    content = await upload.read()
    with open(target_path, "wb") as f:
        f.write(content)
    return target_path

The caller constructs target_path by joining the client-supplied multipart filename directly into the uploads directory, without sanitization:

image_api.py:212-214
filename = img.filename if hasattr(img, "filename") else f"image_{idx}"
input_path = await save_image_to_path(
    img, os.path.join(uploads_dir, f"{request_id}_{idx}_{filename}")
)

An unauthenticated attacker can write arbitrary files to any location the server process has access to by sending a filename containing ../ that traverses out of the uploads directory.

CVE-2026-7304Remote code execution via the custom logit processor Critical CVSS 3.1 9.8

SGLang's serving runtime accepts a custom_logit_processor field on its generation endpoints. The field carries a JSON string whose callable property contains a hex-encoded dill payload, which the server deserializes without validation:

custom_logit_processor.py:14-20
@lru_cache(maxsize=None)
def _cache_from_str(json_str: str):
    """Deserialize a json string to a Callable object.
    This function is cached to avoid redundant deserialization.
    """
    data = orjson.loads(json_str)
    return dill.loads(bytes.fromhex(data["callable"]))

An unauthenticated attacker can remotely execute code on any SGLang host that enables the --enable-custom-logit-processor flag by sending a malicious pickle to its generation endpoint.

CVE-2026-3059Duplicate finding Duplicate

The multimodal generation runtime also starts a ZeroMQ broker that binds a REP socket on all interfaces, regardless of --host, and invokes pickle.loads() on every received message:

scheduler_client.py:13-29
async def run_zeromq_broker(server_args: ServerArgs):
    ctx = zmq.asyncio.Context()
    socket = ctx.socket(zmq.REP)
    broker_endpoint = f"tcp://*:{server_args.broker_port}"
    socket.bind(broker_endpoint)  # binds 0.0.0.0 unconditionally

    while True:
        payload = await socket.recv()
        request_batch = pickle.loads(payload)  # untrusted network input
        ...

Antiproof identified this vulnerability independently, and we responsibly disclosed it to the SGLang maintainers on 2026-03-10, alongside the three vulnerabilities above. On 2026-03-11, Orca Security published a blog post covering the same broker vulnerability, tracked as CVE-2026-3059 and credited to Orca.

Disclosure timeline

2026-03-10
Responsibly disclosed all three vulnerabilities to the SGLang maintainers.
2026-03-11
Orca Security published its SGLang advisory, covering CVE-2026-3059.
2026-05-15
CERT/CC published Vulnerability Note VU#777338. The maintainers had not responded. No official patch is available.

Mitigations

As of publication, no official patch is available. Operators are advised not to expose SGLang's service interfaces to untrusted networks.

Acknowledgments

Thanks to Christopher Cullen at CERT/CC for coordinating disclosure and authoring Vulnerability Note VU#777338.