VDB
Sign up
MEDIUM

GHSA-5vjj-2r48-q622

Zapros has an Unbounded Content-Encoding decompression chain that allows denial of service

Quick fix

GHSA-5vjj-2r48-q622 — zapros: upgrade to the fixed version with the command below.

pip install --upgrade 'zapros>=0.14.0'

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.

```python 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: ... ```

Are you affected?

Enter the version of the package you're using.

Affected packages

PyPI/zapros
Introduced in: 0Fixed in: 0.14.0
Fixpip install --upgrade 'zapros>=0.14.0'

References