CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2025-69228
7.50.06%

AIOHTTP Multipart Request Memory Exhaustion DoS

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 28, 2026·5 min read·20 visits

PoC Available

Executive Summary (TL;DR)

The `aiohttp` library failed to correctly accumulate the total size of `multipart/form-data` payloads in its `post()` method. Attackers can exploit this by sending requests composed of numerous small parts that individually satisfy size limits but collectively exhaust server memory. The vulnerability is fixed in version 3.13.3.

A logic error in the `aiohttp` asynchronous HTTP framework allows remote attackers to bypass request size limits (`client_max_size`) using crafted multipart/form-data requests. By failing to cumulatively track the size of incoming fields, the server permits unbounded memory allocation, leading to denial of service via Out-of-Memory (OOM) crashes.

Vulnerability Overview

CVE-2025-69228 identifies a high-severity Denial of Service (DoS) vulnerability in aiohttp, a widely used asynchronous HTTP client/server framework for Python's asyncio. The flaw exists within the server-side request parsing logic, specifically affecting how multipart/form-data bodies are processed when the application calls request.post().

The vulnerability is classified under CWE-770 (Allocation of Resources Without Limits or Throttling). While aiohttp intends to enforce a client_max_size limit to prevent resource exhaustion, a logic error in the implementation renders this protection ineffective against specific payload structures. This allows an unauthenticated remote attacker to force the server to allocate memory far exceeding the configured limits, leading to process termination by the operating system's OOM (Out-of-Memory) killer or general system instability.

Root Cause Analysis

The root cause of this vulnerability lies in the scope of the variable used to track the request body size within aiohttp/web_request.py. The post() method is designed to parse form data and populate a MultiDict. To prevent DoS attacks, it is supposed to check if the total bytes read exceed self._client_max_size.

In the vulnerable implementation, the size variable—intended to act as the accumulator for the total payload size—was initialized to 0 inside the while loop that iterates over the multipart fields. Consequently, the size check validated only the size of the current field against the global limit, rather than the sum of all fields processed so far.

Mathematically, the intended logic was sum(field_sizes) > limit. The actual implemented logic was any(field_size > limit). As long as an attacker splits a massive payload into chunks (fields) smaller than client_max_size, the limit is never triggered, and the server continues to accept data until memory is exhausted.

Code Analysis

The vulnerability is a classic scope error. Below is a comparative analysis of the post() method in aiohttp/web_request.py before and after the fix.

Vulnerable Logic (Pre-3.13.3)

In the vulnerable code, the size variable resets for every iteration of the loop (while field is not None). This prevents the method from tracking the cumulative memory usage of the request.

# aiohttp/web_request.py (Vulnerable)
async def post(self) -> "MultiDictProxy[Union[str, bytes, FileField]]":
    # ... setup ...
    multipart = await self.multipart()
    max_size = self._client_max_size
 
    field = await multipart.next()
    while field is not None:
        size = 0  # <--- CRITICAL FLAW: Resets to 0 for every new field
        field_ct = field.headers.get(hdrs.CONTENT_TYPE)
        
        # ... reading chunk ...
        size += len(chunk)
        if 0 < max_size < size:
            raise HTTPRequestEntityTooLarge
        
        field = await multipart.next()

Patched Logic (3.13.3)

The fix involves moving the initialization of size outside the while loop. This ensures that size persists across iterations, correctly accumulating the total byte count of the entire request body.

# aiohttp/web_request.py (Fixed)
async def post(self) -> "MultiDictProxy[Union[str, bytes, FileField]]":
    # ... setup ...
    multipart = await self.multipart()
    max_size = self._client_max_size
 
    size = 0  # <--- FIX: Initialize once before processing fields
    field = await multipart.next()
    while field is not None:
        # size = 0  <--- REMOVED: Do not reset here
        field_ct = field.headers.get(hdrs.CONTENT_TYPE)
        
        # ... reading chunk ...
        size += len(chunk)
        if 0 < max_size < size:
            raise HTTPRequestEntityTooLarge
        
        field = await multipart.next()

Exploitation Scenario

To exploit this vulnerability, an attacker constructs a multipart/form-data POST request containing thousands of small parts.

Prerequisites:

  1. Target server runs aiohttp <= 3.13.2.
  2. Target endpoint calls await request.post().
  3. client_max_size is configured (default is 1024**2, or 1MB).

Attack Steps:

  1. Preparation: The attacker generates a payload consisting of 50,000 form fields. Each field contains only 500 bytes of random data.
  2. Transmission: The attacker sends this request to the server. The total body size is roughly 25MB (50,000 * 500 bytes) plus overhead.
  3. Bypass: The server processes the first field. size becomes 500. Since 500 < 1MB, it proceeds. The loop repeats. size is reset to 0. The second field is processed. size becomes 500. It proceeds.
  4. Resource Exhaustion: The MultiDict continues to grow. If the attacker scales this to millions of fields (e.g., streaming the request), the server attempts to hold the entire structure in RAM, resulting in a Denial of Service.

Impact Assessment

The primary impact of CVE-2025-69228 is Service Availability Loss.

  • Denial of Service (DoS): The vulnerability allows a single malicious request to consume a disproportionate amount of server memory. In containerized environments (Kubernetes, Docker) where memory limits are strict, this will trigger an immediate OOM Kill of the pod/container. On bare metal, it may cause system-wide instability or swapping.
  • No Data Leakage/Corruption: This vulnerability does not grant unauthorized access to data (Confidentiality) or allow data modification (Integrity).
  • CVSS v3.1 Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H (Score 7.5). The attack vector is network-based, requires no privileges or user interaction, and has a high impact on availability.

Mitigation & Remediation

The only complete remediation is to upgrade the vulnerable library. The logic error is internal to the aiohttp codebase and cannot be fully mitigated by configuration changes within the application logic itself if request.post() is used.

Immediate Action: Upgrade aiohttp to version 3.13.3 or later. This version correctly implements cumulative size tracking.

Defense in Depth (WAF): If an immediate upgrade is not feasible, a Web Application Firewall (WAF) can mitigate the attack by enforcing strict limits on:

  1. Total Request Body Size: Enforce a hard limit on the Content-Length header (though chunked transfer encoding may bypass this if the WAF does not buffer).
  2. Multipart Boundary Count: Inspect the payload and block requests containing an excessive number of multipart boundaries (e.g., > 100 parts).

Configuration Hardening: Version 3.13.3 also introduces new parameters to further harden multipart handling. Developers should review and configure:

  • max_field_size: Maximum size for a single field.
  • max_parts: Maximum number of multipart parts allowed.

Official Patches

aio-libsGitHub Commit fixing the issue
aio-libsOfficial Security Advisory

Fix Analysis (1)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.06%
Top 100% most exploited

Affected Systems

aiohttp

Affected Versions Detail

Product
Affected Versions
Fixed Version
aiohttp
aio-libs
<= 3.13.23.13.3
AttributeDetail
CWE IDCWE-770
CVSS v3.17.5 (High)
Attack VectorNetwork
Privileges RequiredNone
ImpactDenial of Service (DoS)
EPSS Score0.0006

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.003Application Exhaustion
Impact
CWE-770
Allocation of Resources Without Limits or Throttling

Vulnerability Timeline

Fix committed to master branch
2026-01-03
GitHub Security Advisory published
2026-01-05
CVE published in NVD
2026-01-06

References & Sources

  • [1]GHSA-6jhg-hg63-jvvf
  • [2]NVD - CVE-2025-69228

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.