Low severityOSV Advisory· Published Jan 5, 2026· Updated Jan 6, 2026
AIOHTTP Vulnerable to Cookie Parser Warning Storm
CVE-2025-69230
Description
AIOHTTP is an asynchronous HTTP client/server framework for asyncio and Python. In versions 3.13.2 and below, reading multiple invalid cookies can lead to a logging storm. If the cookies attribute is accessed in an application, then an attacker may be able to trigger a storm of warning-level logs using a specially crafted Cookie header. This issue is fixed in 3.13.3.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
aiohttpPyPI | < 3.13.3 | 3.13.3 |
Affected products
1Patches
164629a0834f9[PR #11890/384a1730 backport][3.13] Log once per cookie header (#11909)
3 files changed · +38 −11
aiohttp/_cookie_helpers.py+8 −4 modified@@ -184,6 +184,7 @@ def parse_cookie_header(header: str) -> List[Tuple[str, Morsel[str]]]: i = 0 n = len(header) + invalid_names = [] while i < n: # Use the same pattern as parse_set_cookie_headers to find cookies match = _COOKIE_PATTERN.match(header, i) @@ -201,9 +202,7 @@ def parse_cookie_header(header: str) -> List[Tuple[str, Morsel[str]]]: # Validate the name (same as regex path) if not _COOKIE_NAME_RE.match(key): - internal_logger.warning( - "Can not load cookie: Illegal cookie name %r", key - ) + invalid_names.append(key) else: morsel = Morsel() morsel.__setstate__( # type: ignore[attr-defined] @@ -221,7 +220,7 @@ def parse_cookie_header(header: str) -> List[Tuple[str, Morsel[str]]]: # Validate the name if not key or not _COOKIE_NAME_RE.match(key): - internal_logger.warning("Can not load cookie: Illegal cookie name %r", key) + invalid_names.append(key) continue # Create new morsel @@ -237,6 +236,11 @@ def parse_cookie_header(header: str) -> List[Tuple[str, Morsel[str]]]: cookies.append((key, morsel)) + if invalid_names: + internal_logger.debug( + "Cannot load cookie. Illegal cookie names: %r", invalid_names + ) + return cookies
tests/test_cookie_helpers.py+13 −7 modified@@ -1,5 +1,6 @@ """Tests for internal cookie helper functions.""" +import logging import sys import time from http.cookies import ( @@ -1444,14 +1445,16 @@ def test_parse_cookie_header_illegal_names(caplog: pytest.LogCaptureFixture) -> """Test parse_cookie_header warns about illegal cookie names.""" # Cookie name with comma (not allowed in _COOKIE_NAME_RE) header = "good=value; invalid,cookie=bad; another=test" - result = parse_cookie_header(header) + with caplog.at_level(logging.DEBUG): + result = parse_cookie_header(header) # Should skip the invalid cookie but continue parsing assert len(result) == 2 assert result[0][0] == "good" assert result[0][1].value == "value" assert result[1][0] == "another" assert result[1][1].value == "test" - assert "Can not load cookie: Illegal cookie name 'invalid,cookie'" in caplog.text + assert "Cannot load cookie. Illegal cookie name" in caplog.text + assert "'invalid,cookie'" in caplog.text def test_parse_cookie_header_large_value() -> None: @@ -1554,7 +1557,8 @@ def test_parse_cookie_header_invalid_name_in_fallback( """Test that fallback parser rejects cookies with invalid names.""" header = 'normal=value; invalid,name={"x":"y"}; another=test' - result = parse_cookie_header(header) + with caplog.at_level(logging.DEBUG): + result = parse_cookie_header(header) assert len(result) == 2 @@ -1566,16 +1570,17 @@ def test_parse_cookie_header_invalid_name_in_fallback( assert name2 == "another" assert morsel2.value == "test" - assert "Can not load cookie: Illegal cookie name 'invalid,name'" in caplog.text + assert "Cannot load cookie. Illegal cookie name" in caplog.text + assert "'invalid,name'" in caplog.text def test_parse_cookie_header_empty_key_in_fallback( caplog: pytest.LogCaptureFixture, ) -> None: """Test that fallback parser logs warning for empty cookie names.""" header = 'normal=value; ={"malformed":"json"}; another=test' - - result = parse_cookie_header(header) + with caplog.at_level(logging.DEBUG): + result = parse_cookie_header(header) assert len(result) == 2 @@ -1587,7 +1592,8 @@ def test_parse_cookie_header_empty_key_in_fallback( assert name2 == "another" assert morsel2.value == "test" - assert "Can not load cookie: Illegal cookie name ''" in caplog.text + assert "Cannot load cookie. Illegal cookie name" in caplog.text + assert "''" in caplog.text @pytest.mark.parametrize(
tests/test_web_request.py+17 −0 modified@@ -1,5 +1,6 @@ import asyncio import datetime +import logging import socket import time from collections.abc import MutableMapping @@ -380,6 +381,22 @@ def test_request_cookies_edge_cases() -> None: assert req.cookies == {"test": "quoted value", "normal": "unquoted"} +def test_request_cookies_many_invalid(caplog: pytest.LogCaptureFixture) -> None: + """Test many invalid cookies doesn't cause too many logs.""" + bad = "bad" + chr(1) + "name" + cookie = "; ".join(f"{bad}{i}=1" for i in range(3000)) + req = make_mocked_request("GET", "/", headers=CIMultiDict(COOKIE=cookie)) + + with caplog.at_level(logging.DEBUG): + cookies = req.cookies + + assert len(caplog.record_tuples) == 1 + _, level, msg = caplog.record_tuples[0] + assert level is logging.DEBUG + assert "Cannot load cookie" in msg + assert cookies == {} + + def test_request_cookies_no_500_error() -> None: """Test that cookies with special characters don't cause 500 errors.
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-fh55-r93g-j68gghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-69230ghsaADVISORY
- github.com/aio-libs/aiohttp/commit/64629a0834f94e46d9881f4e99c41a137e1f3326ghsax_refsource_MISCWEB
- github.com/aio-libs/aiohttp/security/advisories/GHSA-fh55-r93g-j68gghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.