{"id":"CVE-2026-61652","aliases":["EUVD-2026-84175","GHSA-6cp7-3m3c-5x5c","PYSEC-2026-4182"],"status":"published","title":"Zapros: Streaming decoders ignored the requested chunk size, allowing a single compressed response chunk to allocate unbounded memory (decompression bomb)","description":"Zapros, a Python HTTP client, prior to version 0.14.0 is vulnerable to denial of service via memory exhaustion. The issue affects all callers who streamed compressed responses relying on the chunk size — explicit (`iter_bytes(chunk_size=...)`) 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. Version 0.14.0 contains a patch. Some workarounds are available. Read the still-compressed body with `Response.iter_raw()` / `Response.async_iter_raw()`, which bypass the built-in decoders, and decompress it yourself with an explicit output-size bound (e.g. `zlib`'s `max_length`), 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.","severity":{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.00436,"percentile":0.38138,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-770"],"published":"2026-09-21T21:13:26Z","modified":"2026-10-28T02:30:27Z","fixes":[{"ecosystem":"PyPI","package":"zapros","fixed_in":["0.14.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"PyPI","package":"zapros","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.14.0"}]}]},{"source":"osv","ecosystem":"PyPI","package":"zapros","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.14.0"}]}],"versions":["0.10.0","0.11.0","0.11.1","0.12.0","0.13.0","0.2.0","0.2.1","0.2.2","0.2.3","0.3.0","0.4.0","0.5.0","0.5.1","0.6.0","0.7.0","0.8.0","0.9.0"]},{"source":"osv","ecosystem":"PyPI","package":"zapros","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.14.0"}]}],"versions":["0.10.0","0.11.0","0.11.1","0.12.0","0.13.0","0.2.0","0.2.1","0.2.2","0.2.3","0.3.0","0.4.0","0.5.0","0.5.1","0.6.0","0.7.0","0.8.0","0.9.0"]}],"products":[{"vendor":"kap-sh","product":"zapros"}],"references":[{"url":"https://github.com/kap-sh/zapros/security/advisories/GHSA-6cp7-3m3c-5x5c","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-61652","tags":["advisory"]},{"url":"https://github.com/kap-sh/zapros/commit/9b59fa65857734599c34b0b3dff4c2b62293a68d","tags":["web"]},{"url":"https://github.com/kap-sh/zapros/releases/tag/v0.14.0","tags":["web"]},{"url":"https://github.com/advisories/GHSA-6cp7-3m3c-5x5c","tags":["advisory"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/61xxx/CVE-2026-61652.json","tags":["advisory"]},{"url":"https://github.com/kap-sh/zapros","tags":["package"]},{"url":"https://pypi.org/project/zapros","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-61652","title":"Zapros: Streaming decoders ignored the requested chunk size, allowing a single compressed response chunk to allocate unbounded memory (decompression bomb)","description":"Zapros, a Python HTTP client, prior to version 0.14.0 is vulnerable to denial of service via memory exhaustion. The issue affects all callers who streamed compressed responses relying on the chunk size — explicit (`iter_bytes(chunk_size=...)`) 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. Version 0.14.0 contains a patch. Some workarounds are available. Read the still-compressed body with `Response.iter_raw()` / `Response.async_iter_raw()`, which bypass the built-in decoders, and decompress it yourself with an explicit output-size bound (e.g. `zlib`'s `max_length`), 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.","status":"published","published":"2026-09-21T21:13:26.969Z","modified":"2026-09-22T14:41:07.283Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","level":"high","assessor":"cna"}],"cwes":["CWE-770"],"updated_at":"2026-11-02T14:19:53.786088Z"}],"euvd":[{"id":"EUVD-2026-84175","description":"Zapros, a Python HTTP client, prior to version 0.14.0 is vulnerable to denial of service via memory exhaustion. The issue affects all callers who streamed compressed responses relying on the chunk size — explicit (`iter_bytes(chunk_size=...)`) 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. Version 0.14.0 contains a patch. Some workarounds are available. Read the still-compressed body with `Response.iter_raw()` / `Response.async_iter_raw()`, which bypass the built-in decoders, and decompress it yourself with an explicit output-size bound (e.g. `zlib`'s `max_length`), 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.","status":"published","published":"2026-09-21T21:13:26Z","modified":"2026-09-22T14:41:07Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","level":"high"}],"updated_at":"2026-11-02T17:28:02.937716Z"}],"ghsa":[{"id":"GHSA-6cp7-3m3c-5x5c","title":"Zapros: Streaming decoders ignored the requested chunk size, allowing a single compressed response chunk to allocate unbounded memory (decompression bomb)","description":"### Impact\n\nDenial of service via memory exhaustion. Affects all callers who streamed compressed responses relying on the chunk size — explicit (`iter_bytes(chunk_size=...)`) 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.\n\n```python\nimport gzip, zapros\n\n# Server returns ~1 GiB of zeros gzip-compressed to ~1 MiB,\n# with header: Content-Encoding: gzip\nbomb = gzip.compress(b\"\\0\" * 1_000_000_000)  # ~1 MiB on the wire\n\nwith zapros.stream(\"GET\", \"https://malicious.example/bomb\") as response:\n    # Caller asks for 8 KiB chunks, expecting bounded memory:\n    for chunk in response.iter_bytes(chunk_size=8192):\n        ...  # first `chunk` is ~1 GiB, not 8 KiB -\u003e memory exhaustion\n```\n\n### Patches\n\nUpgrade to `0.14.0` or later. The decoders now bound the output of each decompression step to the requested `chunk_size`: gzip/deflate via `zlib`'s `max_length` + `unconsumed_tail`, brotli via `output_buffer_limit`, and zstd via a bounded `stream_writer`. Peak memory during streaming decode is now proportional to `chunk_size` for all supported encodings.\n\n### Workarounds\n\nFor unpatched versions:\n- Read the still-compressed body with `Response.iter_raw()` / `Response.async_iter_raw()`, which bypass the built-in decoders, and decompress it yourself with an explicit output-size bound (e.g. `zlib`'s `max_length`), aborting once a configured limit is exceeded.\n- Where feasible, send `Accept-Encoding: identity` to disable response compression so bodies are not decompressed client-side.\n- Avoid decoding response bodies from untrusted servers.","status":"published","published":"2026-09-23T13:57:48Z","modified":"2026-09-23T13:57:50Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-770"],"updated_at":"2026-11-02T14:41:20.575159Z"}],"nvd":[{"id":"CVE-2026-61652","description":"Zapros, a Python HTTP client, prior to version 0.14.0 is vulnerable to denial of service via memory exhaustion. The issue affects all callers who streamed compressed responses relying on the chunk size — explicit (`iter_bytes(chunk_size=...)`) 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. Version 0.14.0 contains a patch. Some workarounds are available. Read the still-compressed body with `Response.iter_raw()` / `Response.async_iter_raw()`, which bypass the built-in decoders, and decompress it yourself with an explicit output-size bound (e.g. `zlib`'s `max_length`), 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.","status":"published","published":"2026-09-21T22:16:57.68Z","modified":"2026-09-24T21:25:27.05Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"high","assessor":"secondary"}],"cwes":["CWE-770"],"updated_at":"2026-11-02T14:12:50.368368Z"}],"osv":[{"id":"CVE-2026-61652","title":"Zapros: Streaming decoders ignored the requested chunk size, allowing a single compressed response chunk to allocate unbounded memory (decompression bomb)","description":"Zapros, a Python HTTP client, prior to version 0.14.0 is vulnerable to denial of service via memory exhaustion. The issue affects all callers who streamed compressed responses relying on the chunk size — explicit (`iter_bytes(chunk_size=...)`) 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. Version 0.14.0 contains a patch. Some workarounds are available. Read the still-compressed body with `Response.iter_raw()` / `Response.async_iter_raw()`, which bypass the built-in decoders, and decompress it yourself with an explicit output-size bound (e.g. `zlib`'s `max_length`), 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.","status":"published","published":"2026-09-21T21:13:26.969Z","modified":"2026-10-28T02:30:27.460211606Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-770"],"updated_at":"2026-11-02T15:45:12.933503Z"},{"id":"GHSA-6cp7-3m3c-5x5c","title":"Zapros: Streaming decoders ignored the requested chunk size, allowing a single compressed response chunk to allocate unbounded memory (decompression bomb)","description":"### Impact\n\nDenial of service via memory exhaustion. Affects all callers who streamed compressed responses relying on the chunk size — explicit (`iter_bytes(chunk_size=...)`) 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.\n\n```python\nimport gzip, zapros\n\n# Server returns ~1 GiB of zeros gzip-compressed to ~1 MiB,\n# with header: Content-Encoding: gzip\nbomb = gzip.compress(b\"\\0\" * 1_000_000_000)  # ~1 MiB on the wire\n\nwith zapros.stream(\"GET\", \"https://malicious.example/bomb\") as response:\n    # Caller asks for 8 KiB chunks, expecting bounded memory:\n    for chunk in response.iter_bytes(chunk_size=8192):\n        ...  # first `chunk` is ~1 GiB, not 8 KiB -\u003e memory exhaustion\n```\n\n### Patches\n\nUpgrade to `0.14.0` or later. The decoders now bound the output of each decompression step to the requested `chunk_size`: gzip/deflate via `zlib`'s `max_length` + `unconsumed_tail`, brotli via `output_buffer_limit`, and zstd via a bounded `stream_writer`. Peak memory during streaming decode is now proportional to `chunk_size` for all supported encodings.\n\n### Workarounds\n\nFor unpatched versions:\n- Read the still-compressed body with `Response.iter_raw()` / `Response.async_iter_raw()`, which bypass the built-in decoders, and decompress it yourself with an explicit output-size bound (e.g. `zlib`'s `max_length`), aborting once a configured limit is exceeded.\n- Where feasible, send `Accept-Encoding: identity` to disable response compression so bodies are not decompressed client-side.\n- Avoid decoding response bodies from untrusted servers.","status":"published","published":"2026-09-23T13:57:48Z","modified":"2026-10-01T17:55:49.14925552Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-770"],"updated_at":"2026-11-02T15:46:39.618611Z"},{"id":"PYSEC-2026-4182","title":"Zapros: Streaming decoders ignored the requested chunk size, allowing a single compressed response chunk to allocate unbounded memory (decompression bomb)","description":"### Impact\n\nDenial of service via memory exhaustion. Affects all callers who streamed compressed responses relying on the chunk size — explicit (`iter_bytes(chunk_size=...)`) 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.\n\n```python\nimport gzip, zapros\n\n# Server returns ~1 GiB of zeros gzip-compressed to ~1 MiB,\n# with header: Content-Encoding: gzip\nbomb = gzip.compress(b\"\\0\" * 1_000_000_000)  # ~1 MiB on the wire\n\nwith zapros.stream(\"GET\", \"https://malicious.example/bomb\") as response:\n    # Caller asks for 8 KiB chunks, expecting bounded memory:\n    for chunk in response.iter_bytes(chunk_size=8192):\n        ...  # first `chunk` is ~1 GiB, not 8 KiB -\u003e memory exhaustion\n```\n\n### Patches\n\nUpgrade to `0.14.0` or later. The decoders now bound the output of each decompression step to the requested `chunk_size`: gzip/deflate via `zlib`'s `max_length` + `unconsumed_tail`, brotli via `output_buffer_limit`, and zstd via a bounded `stream_writer`. Peak memory during streaming decode is now proportional to `chunk_size` for all supported encodings.\n\n### Workarounds\n\nFor unpatched versions:\n- Read the still-compressed body with `Response.iter_raw()` / `Response.async_iter_raw()`, which bypass the built-in decoders, and decompress it yourself with an explicit output-size bound (e.g. `zlib`'s `max_length`), aborting once a configured limit is exceeded.\n- Where feasible, send `Accept-Encoding: identity` to disable response compression so bodies are not decompressed client-side.\n- Avoid decoding response bodies from untrusted servers.","status":"published","published":"2026-10-01T16:38:38.425485Z","modified":"2026-10-01T17:45:09.3272361Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","level":"high"}],"updated_at":"2026-11-02T15:52:57.671918Z"}]}}
