GHSA-5VJJ-2R48-Q622
Vulnerability from github – Published: 2026-09-23 13:58 – Updated: 2026-09-23 13:58Impact
Who is impacted: - Any application using Zapros to make HTTP requests to untrusted servers - Applications that follow redirects to attacker-controlled hosts
Attack vector: - 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.
Patches
Fixed in version 0.14.0.
The fix adds a hardcoded limit of 5 Content-Encoding layers. Responses exceeding this limit raise DecodingError.
Workarounds
Add middleware that checks for a malicious Content-Encoding header.
from typing import cast
from zapros import (
AsyncBaseHandler,
AsyncBaseMiddleware,
BaseHandler,
BaseMiddleware,
Client,
DecodingError,
Request,
Response,
)
MAX_DECODE_LAYERS = 5
class ContentEncodingCheckMiddleware(BaseMiddleware, AsyncBaseMiddleware):
def __init__(
self,
next_handler: BaseHandler | AsyncBaseHandler,
*,
max_layers: int = MAX_DECODE_LAYERS,
) -> None:
self.next = cast(BaseHandler, next_handler)
self.async_next = cast(AsyncBaseHandler, next_handler)
self._max_layers = max_layers
def _check(self, response: Response) -> None:
encoding_header = response.headers.get("Content-Encoding")
if not encoding_header:
return
layers = [enc.strip().lower() for enc in encoding_header.split(",") if enc.strip()]
if len(layers) > self._max_layers:
raise DecodingError(f"Too many Content-Encoding layers ({len(layers)}), maximum is {self._max_layers}")
def handle(self, request: Request) -> Response:
response = self.next.handle(request)
self._check(response)
return response
async def ahandle(self, request: Request) -> Response:
response = await self.async_next.ahandle(request)
self._check(response)
return response
with Client().wrap_with_middleware(lambda next: ContentEncodingCheckMiddleware(next)) as client:
...
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "zapros"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.14.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-61541"
],
"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"
},
"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 ) -\u003e 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) -\u003e 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) \u003e 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) -\u003e Response:\n response = self.next.handle(request)\n self._check(response)\n return response\n\n async def ahandle(self, request: Request) -\u003e 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```",
"id": "GHSA-5vjj-2r48-q622",
"modified": "2026-09-23T13:58:35Z",
"published": "2026-09-23T13:58:35Z",
"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"
}
],
"schema_version": "1.4.0",
"severity": [
{
"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",
"type": "CVSS_V4"
}
],
"summary": "Zapros has an Unbounded Content-Encoding decompression chain that allows denial of service"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.