From 83df62e97efcb8b2b306c39bda3458566be454b2 Mon Sep 17 00:00:00 2001 From: prasanna8585 Date: Sun, 21 Jun 2026 19:50:03 +0530 Subject: [PATCH] security: Add max_length to zlib.decompress in uworker_io.py A compromised or malicious uworker process could upload a zlib- compressed decompression bomb to its signed GCS output URL. The trusted tworker, which explicitly treats uworker output as untrusted, was calling zlib.decompress() on this data without any size limit. This could cause an OOM crash on the tworker, disrupting ClusterFuzz orchestration. Add _MAX_UWORKER_MSG_SIZE (256 MB) as an upper bound on all three zlib.decompress() calls in uworker_io.py (lines 129, 170, 184). The existing except zlib.error blocks handle the new zlib.error that decompress raises when the limit is exceeded, so no additional error handling is required. Fixes: decompression bomb DoS via untrusted uworker output --- .../_internal/bot/tasks/utasks/uworker_io.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/clusterfuzz/_internal/bot/tasks/utasks/uworker_io.py b/src/clusterfuzz/_internal/bot/tasks/utasks/uworker_io.py index 7380a512890..0f311b4bac2 100644 --- a/src/clusterfuzz/_internal/bot/tasks/utasks/uworker_io.py +++ b/src/clusterfuzz/_internal/bot/tasks/utasks/uworker_io.py @@ -19,6 +19,11 @@ import uuid import zlib +# Maximum decompressed size for uworker messages (256 MB). +# Prevents a malicious or compromised uworker from causing an OOM +# on the trusted tworker via a zlib decompression bomb. +_MAX_UWORKER_MSG_SIZE = 256 * 1024 * 1024 + from google.cloud import ndb from google.cloud.datastore_v1.types import entity as entity_pb2 from google.cloud.ndb import model @@ -126,7 +131,7 @@ def download_and_deserialize_uworker_input( download URL.""" data = storage.download_signed_url(uworker_input_download_url) try: - data = zlib.decompress(data) + data = zlib.decompress(data, max_length=_MAX_UWORKER_MSG_SIZE) except zlib.error: # This is for backward compatiblity during the merge. # TOOD(metzman): Remove backward compatibility efforts when every @@ -167,7 +172,8 @@ def download_input_based_on_output_url( input_url = uworker_output_path_to_input_path(output_url) data = storage.read_data(input_url) try: - serialized_uworker_input = zlib.decompress(data) + serialized_uworker_input = zlib.decompress( + data, max_length=_MAX_UWORKER_MSG_SIZE) except zlib.error: # For backwards compatability support uncompressed. serialized_uworker_input = data @@ -181,7 +187,8 @@ def download_and_deserialize_uworker_output( """Downloads and deserializes uworker output.""" data = storage.read_data(output_url) try: - serialized_uworker_output = zlib.decompress(data) + serialized_uworker_output = zlib.decompress( + data, max_length=_MAX_UWORKER_MSG_SIZE) except zlib.error: # For backwards compatability support uncompressed. serialized_uworker_output = data