pypi / aiohttp
aiohttp
What changed in aiohttp 3, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-17.
aiohttp 3170 changes
Breaking changes 25
Rejects HTTP and HTTPS absolute-form targets without // or with an empty host.
Stalled first request bodies now close connections, while actively arriving bodies extend the deadline.
Pure-Python parsing now rejects control characters in request targets, matching the llhttp-backed parser.
The receive queue keeps only a weak reference while parsing is stalled, so direct users must retain the reader.
The minimum supported yarl version is now 1.25.1.
Multipart Content-Length values must contain only decimal digits, matching the main request parser.
load now replaces jar contents instead of merging them with existing state.
Loaded cookies now use update_cookies acceptance rules, including rejecting IP-address cookies without unsafe=True.
read_nowait now returns only chunks buffered when the call started, keeping automatic body draining bounded.
readany now returns only chunks buffered when the call started, keeping automatic body draining bounded.
Legacy non-canonical numeric IPv4 forms are rejected; only canonical dotted-quad literals are treated as IP addresses.
Missing Host headers now fall back to the local socket address or an empty string instead of reverse DNS.
Redirects with consumed non-rewindable bodies now raise ClientPayloadError instead of sending an empty body.
Cookies containing ASCII control characters are skipped instead of propagating CookieError.
CookieJar.save now writes JSON format and protects saved files with restrictive permissions.
Adds an API for encoding HTTP Basic Authentication credentials.
Outbound status lines and headers now reject all forbidden ASCII control characters with ValueError.
Python 3.9 is no longer supported.
Pure-Python request header validation now follows RFC 9110 control-character handling while response parsing remains lax.
The C extension parser now rejects duplicate singleton headers, matching the pure Python parser and preventing parser-differential access-control bypasses.
Malformed chunked transfer encoding now raises TransferEncodingError instead of hanging indefinitely.
Brotli minimum version is now 1.2.
brotlicffi minimum version is now 1.2.
Decompression now defaults to a maximum output size of 32MiB per decompress call.
Python versions below 3.14 now require backports.zstd instead of zstandard for zstd support.
Security 48
The web server no longer trusts the scheme supplied in an absolute-form request target.
Discarded data after a WebSocket frame protocol error no longer grows without bound; read_bufsize also bounds pre-reader data.
Reduces CPU consumption and rejects large numbers of concatenated compressed members.
Secure shared cookies are no longer sent over unencrypted connections.
Secure per-request cookies are now sent to origins configured as treat_as_secure_origin.
Prevents integer overflow when processing messages that are too large.
Each Set-Cookie header now creates one cookie and ignores unrecognized attributes, preventing attacker-controlled cookie-object growth.
Rejects a new data frame inserted between fragments of an in-progress message as a protocol error.
AIOHTTP: Out-of-bounds heap read in C HTTP response parser error path (malformed chunked response)
AIOHTTP: HTTP request smuggling via WebSocket upgrade
AIOHTTP: WebSocket client accepts compressed frames without negotiated permessage-deflate
The Python parser now rejects a bare LF in the request line.
aiohttp: C HTTP Parser Bypasses max_line_size for Fragmented Lines
aiohttp: DigestAuthMiddleware Applies Credentials to Cross-Origin Redirect Challenges
aiohttp: Host-Only Cookies Become Domain Cookies After CookieJar Persistence
aiohttp: HTTP/1 Pipelined Requests Queue Without Limit
aiohttp: Incomplete websocket frame payloads bypass memory limits
aiohttp: Payload Response Resources Are Not Closed After Mid-Body Disconnect
aiohttp: TLS Server Hostname Override Is Ignored When Reusing HTTPS Connections
aiohttp: Unread Compressed Request Bodies Bypass client_max_size During Cleanup
Persisted cookies retain the host-only flag, keeping cookies without Domain scoped to their exact host after reload.
Digest credentials are scoped to the first request origin, preventing credentials from being used for unrelated redirect origins.
The pure-Python HTTP parser now enforces max_line_size when a complete chunk-size line arrives in one read.
Parsed but unhandled pipelined requests are bounded per connection, preventing unbounded server backlog while one handler is busy.
aiohttp: CRLF injection in multipart headers
AIOHTTP is vulnerable to cross-origin redirect with per-request cookies
AIOHTTP is Vulnerable to Deserialization of Untrusted Data
Highly compressed valid payloads are decompressed safely in chunks of 256+ KiB.
Saved cookie files now use 0x600 permissions to limit access by other users.
AIOHTTP accepts duplicate Host headers
AIOHTTP Affected by Denial of Service (DoS) via Unbounded DNS Cache in TCPConnector
AIOHTTP affected by UNC SSRF/NTLMv2 Credential Theft/Local File Read in static resource handler on Windows
aiohttp allows unlimited trailer headers, leading to possible uncapped memory usage
AIOHTTP has a Multipart Header Size Bypass
AIOHTTP has CRLF injection through multipart part content type header construction
AIOHTTP has HTTP response splitting via \r in reason phrase
AIOHTTP has late size enforcement for non-file multipart fields causes memory DoS
AIOHTTP leaks Cookie and Proxy-Authorization headers on cross-origin redirect
AIOHTTP's C parser (llhttp) accepts null bytes and control characters in response header values - header injection/security bypass
AIOHTTP has unicode match groups in regexes for ASCII protocol elements
AIOHTTP's HTTP Parser auto_decompress feature is vulnerable to zip bomb
AIOHTTP's unicode processing of header values could cause parsing discrepancies
AIOHTTP vulnerable to brute-force leak of internal static file path components
AIOHTTP Vulnerable to Cookie Parser Warning Storm
AIOHTTP vulnerable to denial of service through large payloads
AIOHTTP vulnerable to DoS through chunked messages
AIOHTTP vulnerable to DoS when bypassing asserts
The parser now raises an exception for a continuation frame without an initial frame in context.
Deprecations 4
Deprecated in favor of aiohttp.UploadTracker.
Deprecated in favor of aiohttp.UploadTracker.
The built-in pytest plugin is deprecated; projects should switch to pytest-aiohttp.
BasicAuth is deprecated; use encode_basic_auth with an Authorization header.
New APIs and options 19
Custom writers must invoke on_body_write with each accepted body chunk length or Payload.bytes_written remains zero.
Adds constants for widely used browser, tracing, security, caching, RFC, proxy, and application headers.
Adds an API for observing client request upload progress.
Adds a cap on form fields accepted by BaseRequest.post; the default is 1000 and 0 disables the cap.
Adds access to the response output size.
Adds access to whether response upload completion has occurred.
Exposes stored cookies and their full attributes through a read-only property.
Exposes host-only cookie state through a read-only property.
Allows WebSocket TEXT messages to be received as raw bytes for direct use with high-performance JSON parsers.
Adds a response helper for bytes-returning JSON serialization.
Adds an explicit type for bytes-returning JSON serializers.
Adds a payload type for bytes-returning JSON serialization.
Adds statically typed request context storage keys, matching AppKey behavior.
Adds statically typed response context storage keys, matching AppKey behavior.
Exposes the dynamically allocated TCP port.
Added an async generator for non-blocking decompression of large multipart payloads.
Added a TCPConnector parameter to limit the DNS cache size.
Added a parameter to limit the number of headers read from a response.
AppRunner configuration options are now also available when using run_app().
Performance 3
Uses spooled temporary files to reduce the number of file descriptors required.
Fixes excessive memory consumption for small WebSocket messages.
Bounds per-read overhead while reassembling fragmented WebSocket frames.
Behavior and default changes 6
Cookie parsing, storage, and generated Cookie headers are bounded with Firefox-style eviction.
Cleanup contexts may now be asynchronous context managers; legacy single-yield generators remain supported.
CookieJar.load tries JSON first and falls back to a restricted pickle unpickler.
Compressed payloads now run asynchronously by default because the default threshold changed.
Response parsing in lax mode now skips duplicate singleton header checks; strict mode continues enforcing RFC 9110 singletons.
Multipart processing chunks increased from 64 KiB to 256KiB to better match aiohttp internals.
Tooling 2
An installable pure-Python wheel is published for platforms without a working compiler or matching binary wheel.
Wheels are now available for Android and iOS platforms.
Fixes and other changes 63
WebSocket connections no longer fail when control frames have RSV1 set after permessage-deflate negotiation.
Domain routing now handles Host ports and uppercase wildcard domains correctly.
Using keepalive_timeout=None no longer crashes on the second request to the same host.
Accepts range units without regard to letter case.
Multipart parts with Content-Length 0 now immediately yield an empty chunk.
Prevents a segmentation fault on Python 3.12 and newer when decompression errors occur while draining data.
Header values now have trailing whitespace stripped consistently with the pure-Python parser and RFC 9110.
Stops the parser from raising ClientPayloadError when a complete Content-Length body is pending completion.
Cancelled or failed requests waiting for 100 Continue no longer leave corrupted connections eligible for reuse.
Mixed-case encoding values such as Gzip are accepted and decompressed correctly.
Copies mutable Morsel objects supplied by callers.
Prevents possible event loop state corruption on Python 3.12 and newer.
The pure-Python request parser now reads a body in HEAD requests.
Requests behind declined upgrades no longer remain unanswered or get served more than once.
Internally retried requests no longer send truncated bodies when request data is a file object.
Fixes overlapping slots and broken slots inheritance affecting request handling and response classes.
Finds multibyte separators split across chunks without returning data past the separator.
Accepts compressed data frames when a control frame arrives before the first data frame.
Redirects crossing an origin no longer drop all but the first Authorization, Cookie, or Proxy-Authorization header.
The client now closes cleanly after an exception.
Optional whitespace in Content-Disposition headers is parsed correctly.
Unknown charsets in extended multipart parameters no longer escape parsing as LookupError or UnicodeDecodeError.
An empty authentication domain no longer raises IndexError.
Digest challenges remain valid when WWW-Authenticate offers multiple schemes.
Digest authentication escaping now handles backslashes in challenge values.
Control frames no longer break fragmented WebSocket messages.
The worker no longer endlessly reloads when application startup fails.
The C parser now recognizes newer HTTP methods such as QUERY.
The pure-Python HTTP parser no longer raises IndexError for affected input.
Datetime values with fractional seconds are no longer rounded down incorrectly.
Windows resolution falls back without AI_ADDRCONFIG when the first lookup fails.
The C parser no longer folds a fragment into the query string when the query is empty.
Empty header parameter values no longer raise IndexError.
Optional whitespace around the disposition type is accepted before token validation.
The client no longer decompresses WebSocket frames when compression was not negotiated.
Request method handling now has consistent case sensitivity.
Read timeouts are no longer left pending on idle pooled keep-alive connections.
Request bodies are now read when WebSocket upgrades are rejected.
CancelledError now closes the associated connection.
Absolute expiration deadlines are persisted, so reloaded cookies keep their original lifetime.
Closing during in-flight DNS resolution now raises ClientConnectionError instead of AttributeError.
WebSocket parser validation was tightened.
Digest signatures now use the encoded request-target sent on the wire.
Inbound data resets the heartbeat timer, preventing false ping/pong timeouts during large frames.
Concatenated gzip and deflate members are now fully decompressed using fresh decompressors.
Access log timestamps now reflect daylight saving time transitions.
Fixed the running-event-loop error when using this worker on Python 3.14 and newer.
Fixed the running-event-loop error when using this worker on Python 3.14 and newer.
Restored decode as a synchronous method for backward compatibility after it was changed to async in 3.13.3.
Accessing os_error no longer raises AttributeError.
ClientTimeout(total=0) no longer raises ValueError when creating a TLS connection.
The pure-Python request parser now splits comma-separated and repeated Connection values for keep-alive, close, and upgrade handling.
Digest authentication now preserves challenge fields whose values are empty strings.
Passing enable_cleanup_closed to TCPConnector on Python 3.12.7 no longer emits a false-positive DeprecationWarning.
Multipart reading no longer fails when it encounters an empty body part.
Proxy authorization headers are now passed when reusing a connection, preventing 407 errors.
Continues parsing subsequent cookies after a malformed cookie fails regex validation.
Makes compressed sends cancellation safe by shielding compression and preserving compressor state.
Routing to a sub-application added with add_domain() now works when the parent app has the same path.
Invalid Content-Type syntax now produces application/octet-stream.
netrc file lookup no longer performs blocking I/O in the event loop.
Python 3.14 now works when aiohttp is built without zstd support.
Decompression is fixed for chunked zstd streams.