GHSA-6cp7-3m3c-5x5c: Pip/zapros vulnerability
Impact
Denial of service via memory exhaustion. Affects all callers who streamed compressed responses relying on the chunk size — explicit (iterbytes(chunksize=...)) or the default — to bound memory. The decoder ignored that bound, so a chunk could be far larger than requested and a single compressed response could overflow memory.
python import gzip, zapros
Server returns ~1 GiB of zeros gzip-compressed to ~1 MiB, with header: Content-Encoding: gzip bomb = gzip.compress(b"\0" 1000000000) # ~1 MiB on the wire
with zapros.stream("GET", "https://malicious.example/bomb") as response: # Caller asks for 8 KiB chunks, expecting bounded memory: for chunk in response.iterbytes(chunksize=8192): ... # first chunk is ~1 GiB, not 8 KiB -> memory exhaustion
Patches
Upgrade to 0.14.0 or later. The decoders now bound the output of each decompression step to the requested chunksize: gzip/deflate via zlib's maxlength + unconsumedtail, brotli via outputbufferlimit, and zstd via a bounded streamwriter. Peak memory during streaming decode is now proportional to chunksize for all supported encodings.
Workarounds
For unpatched versions: - Read the still-compressed body with Response.iterraw() / Response.asynciterraw(), which bypass the built-in decoders, and decompress it yourself with an explicit output-size bound (e.g. zlib's maxlength), aborting once a configured limit is exceeded. - Where feasible, send Accept-Encoding: identity to disable response compression so bodies are not decompressed client-side. - Avoid decoding response bodies from untrusted servers.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/zaprosto a version that resolves this vulnerability.Fixed in 0.14.0 - Upgrade
Upgrade
zaprosto a version that resolves this vulnerability.Fixed in 0.14.0 - Configuration
Where feasible, send Accept-Encoding: identity to disable response compression and prevent client-side decompression.
zapros response requests Accept-Encoding = identity - Compensating control
Avoid decoding response bodies from untrusted servers.
- Compensating control
Read compressed response bodies with Response.iter_raw() or Response.async_iter_raw(), bypass the built-in decoders, decompress manually with an explicit output-size bound, and abort when the configured limit is exceeded.
Event History
Frequently Asked Questions
Are applications using the default streaming chunk size affected?
Yes. The issue affects callers that rely on either an explicit chunk_size passed to iter_bytes() or the default chunk size to limit memory use while streaming compressed responses.
What must an attacker control to trigger the memory exhaustion?
An attacker needs to cause the application to stream a highly compressible response with a supported Content-Encoding, such as a gzip response that expands far beyond its compressed size. A single decoded chunk can then be much larger than the requested chunk size.
What is the remediation?
Upgrade zapros to version 0.14.0 or later. The updated decoders bound decompression output per step to the requested chunk size for gzip, deflate, brotli, and zstd.