The vulnerability is a Denial of Service (DoS) in aiohttp's handling of chunked transfer encoding, as described in GHSA-g84x-mcqj-x9qq. The root cause is twofold. First, the server used a Python list to store the offsets of incoming chunks. When reading the body, it would call list.pop(0) to process the chunks sequentially. This operation has a time complexity of O(n), meaning its execution time grows linearly with the number of chunks. An attacker could send a request with a very large number of tiny chunks, causing this operation to consume excessive CPU time and block the server's event loop.
The second issue was the lack of any limit on the number of chunks that could be buffered. This allowed an attacker to create the conditions for the first issue by building up a very large list of chunk offsets in memory.
The patches address both problems:
- Commit
dc3170b56904bdf814228fae70a5501a42a6c712 replaces the list with a collections.deque, changing the inefficient pop(0) to an efficient popleft() operation with O(1) complexity. This directly mitigates the CPU exhaustion in the readchunk and _read_nowait_chunk methods.
- Commit
4ed97a4e46eaf61bd0f05063245f613469700229 introduces a throttling mechanism based on the number of chunks. In end_http_chunk_receiving, it adds logic to pause reading from the socket if the number of buffered chunks exceeds a new _high_water_chunks limit, preventing the chunk buffer from growing indefinitely.
Therefore, the vulnerable functions are those that either performed the inefficient list operation or failed to prevent the chunk buffer from growing excessively. During exploitation, a profiler would show significant time spent in StreamReader.readchunk and StreamReader._read_nowait_chunk due to the pop(0) calls.