GHSA-5vjj-2r48-q622

Suggest an improvement
Source
https://github.com/advisories/GHSA-5vjj-2r48-q622
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-5vjj-2r48-q622/GHSA-5vjj-2r48-q622.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-5vjj-2r48-q622
Aliases
Published
2026-09-23T13:58:35Z
Modified
2026-09-23T14:15:04Z
Severity
  • 6.9 (Medium) CVSS_V4 - 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 CVSS Calculator
Summary
Zapros has an Unbounded Content-Encoding decompression chain that allows denial of service
Details

Impact

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:
    ...
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"
}
References

Affected packages

PyPI / zapros

Package

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
0.14.0

Affected versions

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
0.10.0
0.11.0
0.11.1
0.12.0
0.13.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"