1 line
3.6 KiB
JSON
1 line
3.6 KiB
JSON
{"schema_version":"1.9.0","id":"GHSA-5vjj-2r48-q622","published":"2026-09-23T13:58:35Z","modified":"2026-10-01T17:56:21.759535591Z","aliases":["CVE-2026-61541","PYSEC-2026-4181"],"summary":"Zapros has an Unbounded Content-Encoding decompression chain that allows denial of service","details":"### Impact\n\n**Who is impacted**:\n - Any application using Zapros to make HTTP requests to untrusted servers\n - Applications that follow redirects to attacker-controlled hosts\n\n**Attack vector**:\n - A malicious HTTP server returns a response with many chained content encodings. When the client attempts to decode, it creates a deeply nested decompression chain consuming excessive resources.\n\n### Patches\n\nFixed in version 0.14.0.\n\n The fix adds a hardcoded limit of **5** `Content-Encoding` layers. Responses exceeding this limit raise `DecodingError`.\n\n### Workarounds\n\nAdd middleware that checks for a malicious Content-Encoding header.\n\n```python\nfrom typing import cast\n\nfrom zapros import (\n AsyncBaseHandler,\n AsyncBaseMiddleware,\n BaseHandler,\n BaseMiddleware,\n Client,\n DecodingError,\n Request,\n Response,\n)\n\nMAX_DECODE_LAYERS = 5\n\n\nclass ContentEncodingCheckMiddleware(BaseMiddleware, AsyncBaseMiddleware):\n def __init__(\n self,\n next_handler: BaseHandler | AsyncBaseHandler,\n *,\n max_layers: int = MAX_DECODE_LAYERS,\n ) -> None:\n self.next = cast(BaseHandler, next_handler)\n self.async_next = cast(AsyncBaseHandler, next_handler)\n self._max_layers = max_layers\n\n def _check(self, response: Response) -> None:\n encoding_header = response.headers.get(\"Content-Encoding\")\n if not encoding_header:\n return\n\n layers = [enc.strip().lower() for enc in encoding_header.split(\",\") if enc.strip()]\n if len(layers) > self._max_layers:\n raise DecodingError(f\"Too many Content-Encoding layers ({len(layers)}), maximum is {self._max_layers}\")\n\n def handle(self, request: Request) -> Response:\n response = self.next.handle(request)\n self._check(response)\n return response\n\n async def ahandle(self, request: Request) -> Response:\n response = await self.async_next.ahandle(request)\n self._check(response)\n return response\n\n\nwith Client().wrap_with_middleware(lambda next: ContentEncodingCheckMiddleware(next)) as client:\n ...\n```","affected":[{"package":{"name":"zapros","ecosystem":"PyPI","purl":"pkg:pypi/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"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-5vjj-2r48-q622/GHSA-5vjj-2r48-q622.json"}}],"references":[{"type":"WEB","url":"https://github.com/kap-sh/zapros/security/advisories/GHSA-5vjj-2r48-q622"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-61541"},{"type":"WEB","url":"https://github.com/kap-sh/zapros/commit/7971fbca9707eb01455ca2d73416ac091f96908b"},{"type":"PACKAGE","url":"https://github.com/kap-sh/zapros"},{"type":"WEB","url":"https://github.com/kap-sh/zapros/releases/tag/v0.14.0"}],"database_specific":{"cwe_ids":["CWE-770"],"github_reviewed":true,"github_reviewed_at":"2026-09-23T13:58:35Z","nvd_published_at":"2026-09-21T22:16:57Z","severity":"MODERATE"},"severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N"}]} |