PyPI / aiohttp / 3.14.5

aiohttp 3.14.5

Source
https://github.com/aio-libs/aiohttp
Tag scanned
v3.14.5
Compared with
v3.14.4 (0 signals introduced since)
Files
241 scanned, 56 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 33 info
Scan time
16.6 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 18 of 18 warn and critical signals; 18 demoted to info.
Disclude version
4.1.0
Scanned (UTC)
2026-10-21 22:34

Signals

Ordered by severity, then signals introduced in this release. Hidden characters are shown as ⟨U+…⟩.

  1. info long-line CHANGES.rst:6908:1

    line length 1260 characters (raw pass, confidence 0.50)

    - `#3927 <https://github.com/aio-libs/aiohttp/issues/3927>`_, `#4247 <https://github.com/aio-libs/aiohttp/issues/4247>`_, `#4247 <https://github.com/aio-libs/aiohttp/issues/4247>`_, `#5389 <https://github.com/aio-libs/aiohttp/issues/5389>`_, `#5457 <https://github.com/aio-libs/aiohttp/issues/5457>`_, `#5486 <https://gi
  2. info warn → info by review unicode-zero-width CHANGES.rst:8193:3

    U+FEFF ZERO WIDTH NO-BREAK SPACE (BOM) in source (raw pass, confidence 0.75)

    - Rename `from_env` to `trust_env` in client reference. (`#2451 <https://github.com/aio-libs/aiohttp/pull/2451>`_)
    - ⟨U+FEFF⟩Fixed mistype in `Proxy Support` section where `trust_env` parameter was
      used in `session.get("http://python.org", trust_env=True)` method instead of
      aiohttp.ClientSession constructor as follows:
    likely benign LLM, confidence 0.85 A byte-order mark was pasted into a changelog entry in the aiohttp docs.
    Reasoning

    A stray U+FEFF byte-order mark sits inside a changelog bullet in a documentation file. This is a common editing artifact with no code execution or hidden instruction, so it is a cosmetic issue rather than obfuscation.

  3. info long-line THREAT_MODEL.md:271:1

    line length 961 characters (raw pass, confidence 0.50)

    | 1.12 | Cython ⇄ pure-Python divergence | `tests/test_http_parser.py` parameterises tests over `REQUEST_PARSERS` / `RESPONSE_PARSERS` (pure-Python always; Cython when the extension imports). The high-leverage attack vectors are already covered under both backends: CL+TE (`test_content_length_transfer_encoding`), CL… (340 bytes total)
  4. info warn → info by review frame-introspection aiohttp/client.py:440:62

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

            if loop.get_debug():
                self._source_traceback = traceback.extract_stack(sys._getframe(1))
    
            if cookie_jar is None:
    likely benign LLM, confidence 0.92 Debug-mode capture of the caller's stack frame for source tracebacks in the client session.
    Reasoning

    sys._getframe(1) is used only when loop debug mode is on, to record a source traceback for unclosed-session warnings. This is standard asyncio debugging practice in aiohttp.

  5. info warn → info by review frame-introspection aiohttp/client_reqrep.py:524:62

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

            if loop.get_debug():
                self._source_traceback = traceback.extract_stack(sys._getframe(1))
    
        def __reset_writer(self, _: object = None) -> None:
    likely benign LLM, confidence 0.92 Debug-mode stack frame capture for request/response source tracebacks.
    Reasoning

    Same guarded debug-only stack capture as in client.py, used to aid diagnostics of unclosed responses or requests. No sensitive action follows.

  6. info warn → info by review frame-introspection aiohttp/client_reqrep.py:1103:62

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

            if loop.get_debug():
                self._source_traceback = traceback.extract_stack(sys._getframe(1))
    
            self.update_version(version)
    likely benign LLM, confidence 0.92 Debug-mode stack frame capture when constructing a client request object.
    Reasoning

    Another instance of the loop-debug-gated source traceback pattern. It only records where an object was created and does not alter behavior.

  7. info warn → info by review decoder-decompress-payload aiohttp/compression_utils.py:143:16

    file imports decoder module(s) zlib and calls `.decompress()` — embedded payload decompressed at runtime (ast pass, confidence 0.75)

        def decompressobj(self, *args: Any, **kwargs: Any) -> ZLibDecompressObjProtocol:
            return self._zlib_backend.decompressobj(*args, **kwargs)
    
        def compress(self, data: Buffer, *args: Any, **kwargs: Any) -> bytes:
    likely benign LLM, confidence 0.90 Compression wrapper delegating to zlib for HTTP content encoding.
    Reasoning

    This is a thin wrapper that forwards decompressobj and compress calls to the zlib backend for HTTP content-encoding support. Decompressing data is the library's purpose and does not indicate an embedded payload.

  8. info warn → info by review frame-introspection aiohttp/connector.py:148:62

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

            if loop.get_debug():
                self._source_traceback = traceback.extract_stack(sys._getframe(1))
    
        def __repr__(self) -> str:
    likely benign LLM, confidence 0.92 Debug-mode stack frame capture for connector source tracebacks.
    Reasoning

    Loop-debug-gated source traceback capture in the connector, identical to the other debug-only frame recordings in the library.

  9. info warn → info by review frame-introspection aiohttp/connector.py:309:62

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

            if loop.get_debug():
                self._source_traceback = traceback.extract_stack(sys._getframe(1))
    
            # Connection pool of reusable connections.
    likely benign LLM, confidence 0.92 Debug-mode stack frame capture in the connector constructor.
    Reasoning

    The same debug-only traceback capture pattern in the connector constructor. It has no effect outside debug mode.

  10. info warn → info by review frame-introspection aiohttp/helpers.py:886:17

    `inspect.currentframe` — call-stack frame introspection (ast pass, confidence 0.70)

            # Prefix with module name to help deduplicate key names.
            frame = inspect.currentframe()
            while frame:
                if frame.f_code.co_name == "<module>":
    likely benign LLM, confidence 0.88 Walks the call stack to determine a module-name prefix for key deduplication.
    Reasoning

    The code walks frames to find the module name, which is used to prefix keys and deduplicate names. It is internal bookkeeping with no network, exec, or hidden behavior.

  11. info warn → info by review decoder-decompress-payload aiohttp/multipart.py:614:25

    file imports decoder module(s) base64, binascii and calls `.decompress()` — embedded payload decompressed at runtime (ast pass, confidence 0.75)

                )
                yield await d.decompress(data, max_length=self._max_decompress_size)
                while d.data_available:
                    yield await d.decompress(b"", max_length=self._max_decompress_size)
    likely benign LLM, confidence 0.90 Streaming decompression of compressed multipart body parts with size limits.
    Reasoning

    This is the streaming decompression path for multipart Content-Encoding bodies, with a max_decompress_size bound. It is the expected handling for compressed HTTP payloads.

  12. info unicode-homoglyph tests/test_client_response.py:469:27

    identifier `тестkey` contains homoglyph candidates: е (0435)→e, с (0441)→c (in string/comment) (raw pass, confidence 0.35)

            fut = loop.create_future()
            fut.set_result('{"тестkey": "пройденvalue"}'.encode("cp1251"))
            return fut
  13. info unicode-mixed-script tests/test_client_response.py:469:27

    identifier `тестkey` mixes scripts: Cyrillic + Latin (in string/comment) (raw pass, confidence 0.40)

            fut = loop.create_future()
            fut.set_result('{"тестkey": "пройденvalue"}'.encode("cp1251"))
            return fut
  14. info unicode-homoglyph tests/test_client_response.py:469:42

    identifier `пройденvalue` contains homoglyph candidates: р (0440)→p, о (043E)→o, е (0435)→e (in string/comment) (raw pass, confidence 0.35)

            fut = loop.create_future()
            fut.set_result('{"тестkey": "пройденvalue"}'.encode("cp1251"))
            return fut
  15. info unicode-mixed-script tests/test_client_response.py:469:42

    identifier `пройденvalue` mixes scripts: Cyrillic + Latin (in string/comment) (raw pass, confidence 0.40)

            fut = loop.create_future()
            fut.set_result('{"тестkey": "пройденvalue"}'.encode("cp1251"))
            return fut
  16. info warn → info by review decoder-decompress-payload tests/test_compression_utils.py:44:16

    file imports decoder module(s) gzip, zlib and calls `.decompress()` — embedded payload decompressed at runtime (ast pass, confidence 0.75)

            self._feeds.append(len(data))
            return self._obj.decompress(data, max_length)
    likely benign LLM, confidence 0.92 Test helper wrapping a zlib decompressor for compression unit tests.
    Reasoning

    A test helper feeding data through a decompressor to verify chunked decompression. It is a normal unit-test fixture.

  17. info warn → info by review payload-bytes-literal tests/test_cookiejar.py:1259:19

    bytes literal contains 945 `\xNN` escapes (64% of content) — binary payload shape (ast pass, confidence 0.85)

            pickled = b"\x80\x04\x95\xc8\x0b\x00\x00\x00\x00\x00\x00\x8c\x0bcollections\x94\x8c\x0bdefaultdict\x94\x93\x94\x8c\x0chttp.cookies\x94\x8c\x0cSimpleCookie\x94\x93\x94\x85\x94R\x94(\x8c\x00\x94h\x08\x86\x94h\x05)\x81\x94\x8c\rshared-cookie\x94h\x03\x8c\x06Morsel\x94\x93\x94)\x81\x94(\x8c\x07expires\x94h\x08\x8c\
    likely benign LLM, confidence 0.75 Pickled cookie-jar bytes used as a fixture for a backward-compatibility test.
    Reasoning

    This is a pickle byte literal of a CookieJar state, used in a test that verifies loading of legacy pickled cookie data. Pickle payloads are a genuine risk category, but the content is a serialized aiohttp/http.cookies structure in a test file, not an exploit or dropper. The escape density is the expected shape of pickle bytes.

  18. info warn → info by review payload-bytes-literal tests/test_cookiejar.py:1261:19

    bytes literal contains 685 `\xNN` escapes (66% of content) — binary payload shape (ast pass, confidence 0.85)

            pickled = b'\x80\x05\x95\x06\x08\x00\x00\x00\x00\x00\x00\x8c\x0bcollections\x94\x8c\x0bdefaultdict\x94\x93\x94\x8c\x0chttp.cookies\x94\x8c\x0cSimpleCookie\x94\x93\x94\x85\x94R\x94(\x8c\x00\x94h\x08\x86\x94h\x05)\x81\x94\x8c\rshared-cookie\x94h\x03\x8c\x06Morsel\x94\x93\x94)\x81\x94(\x8c\x07expires\x94h\x08\x8c\
    likely benign LLM, confidence 0.75 A second pickled cookie-jar fixture covering another pickle protocol version.
    Reasoning

    A second pickled cookie-jar fixture with a different protocol header, consistent with testing compatibility across pickle versions. Its content matches the same benign cookie structure as the first fixture.

  19. info unicode-mixed-script tests/test_http_parser.py:954:65

    identifier `chunKed` mixes scripts: Latin + Other (in string/comment) (raw pass, confidence 0.40)

        # K = Kelvin sign, not valid ascii.
        text = "GET /test HTTP/1.1\r\nHost: a\r\nTransfer-Encoding: chunKed\r\n\r\n"
        with pytest.raises(http_exceptions.BadHttpMessage):
            parser.feed_data(text.encode())
  20. info unicode-mixed-script tests/test_http_parser.py:961:55

    identifier `websocKet` mixes scripts: Latin + Other (in string/comment) (raw pass, confidence 0.40)

        # K = Kelvin sign, not valid ascii.
        text = "GET /test HTTP/1.1\r\nHost: a\r\nUpgrade: websocKet\r\n\r\n"
        messages, upgrade, tail = parser.feed_data(text.encode())
        assert not upgrade
  21. info unicode-mixed-script tests/test_http_parser.py:1125:10

    identifier `zstd` mixes scripts: Latin + Other (in string/comment) (raw pass, confidence 0.40)

        (
            "zstd".encode(),  # "st".upper() == "ST"
            "deflate".encode(),  # "fl".upper() == "FL"
        ),
  22. info unicode-mixed-script tests/test_http_parser.py:1126:10

    identifier `deflate` mixes scripts: Latin + Other (in string/comment) (raw pass, confidence 0.40)

            "zstd".encode(),  # "st".upper() == "ST"
            "deflate".encode(),  # "fl".upper() == "FL"
        ),
    )
  23. info warn → info by review decoder-decompress-payload tests/test_http_writer.py:66:9

    file imports decoder module(s) zlib and calls `.decompress()` — embedded payload decompressed at runtime (ast pass, confidence 0.75)

    def decompress(data: bytes) -> bytes:
        d = ZLibBackend.decompressobj()
        return d.decompress(data)
    likely benign LLM, confidence 0.92 Test helper decompressing zlib output to verify HTTP writer compression.
    Reasoning

    A small test helper that decompresses zlib data to check the writer's compressed output. It is ordinary test code.

  24. info warn → info by review decoder-decompress-payload tests/test_multipart.py:1466:20

    file imports decoder module(s) base64, gzip and calls `.decompress()` — embedded payload decompressed at runtime (ast pass, confidence 0.75)

    
        decompressor = ZLibBackend.decompressobj(wbits=16 + ZLibBackend.MAX_WBITS)
        data = decompressor.decompress(message.split(b"\r\n")[0])
        data += decompressor.flush()
    likely benign LLM, confidence 0.90 Test code that decompresses gzip-wrapped multipart data using zlib's decompressobj.
    Reasoning

    Decompressing a test fixture message with zlib decompressobj in a multipart/compression test is normal; the input is a literal test payload split from a message, not an embedded hidden blob executed at runtime.

  25. info unicode-homoglyph tests/test_urldispatch.py:473:20

    identifier `Fфикс` contains homoglyph candidates: с (0441)→c (in string/comment) (raw pass, confidence 0.35)

        resource = router.add_static(
            "/пре %2Fфикс", pathlib.Path(aiohttp.__file__).parent, name="static"
        )
        assert router["static"] is resource
  26. info unicode-mixed-script tests/test_urldispatch.py:473:20

    identifier `Fфикс` mixes scripts: Latin + Cyrillic (in string/comment) (raw pass, confidence 0.40)

        resource = router.add_static(
            "/пре %2Fфикс", pathlib.Path(aiohttp.__file__).parent, name="static"
        )
        assert router["static"] is resource
  27. info unicode-homoglyph tests/test_urldispatch.py:683:49

    identifier `Fфикс` contains homoglyph candidates: с (0441)→c (in string/comment) (raw pass, confidence 0.35)

        handler = make_handler()
        route = router.add_route("GET", r"/пре %2Fфикс/{arg}", handler)
    
        url = route.url_for(arg="1 2/текст%2F")
  28. info unicode-mixed-script tests/test_urldispatch.py:683:49

    identifier `Fфикс` mixes scripts: Latin + Cyrillic (in string/comment) (raw pass, confidence 0.40)

        handler = make_handler()
        route = router.add_route("GET", r"/пре %2Fфикс/{arg}", handler)
    
        url = route.url_for(arg="1 2/текст%2F")
  29. info unicode-homoglyph tests/test_urldispatch.py:771:21

    identifier `рус` contains homoglyph candidates: р (0440)→p, у (0443)→y, с (0441)→c (in string/comment) (raw pass, confidence 0.35)

        match_info = await router.resolve(req)
        assert {"var": "рус текст"} == match_info
  30. info warn → info by review dynamic-attribute tests/test_web_functional.py:3042:41

    reach-by-name through `locals` (ast pass, confidence 0.60)

        assert resp.status == 200
        assert await resp.text() == str(len(locals()[len_of]))
        await resp.release()
    dismissed LLM, confidence 0.93 Test assertion reads a local variable via locals() to compare response length.
    Reasoning

    locals() lookup by name in an assertion is a trivial test idiom for reading a local variable whose name is set earlier; no execution or hidden behavior.

  31. info warn → info by review decoder-decompress-payload tests/test_web_response.py:657:12

    file imports decoder module(s) gzip and calls `.decompress()` — embedded payload decompressed at runtime (ast pass, confidence 0.75)

        await resp.prepare(req)
        assert gzip.decompress(resp._compressed_body) == body
    likely benign LLM, confidence 0.93 Test checks that a compressed response body decompresses to the expected body.
    Reasoning

    gzip.decompress on the response's compressed body in a test to verify round-trip content is ordinary test verification code.

  32. info warn → info by review dynamic-execution tools/gen.py:16:12

    `compile` called on a non-literal expression (ast pass, confidence 0.70)

        hdrs_file = root / "aiohttp/hdrs.py"
        code = compile(hdrs_file.read_text(), str(hdrs_file), "exec")
        globs = {}
        exec(code, globs)
    likely benign LLM, confidence 0.90 Build helper that execs the project's own hdrs.py module to extract header names.
    Reasoning

    The tool compiles and executes aiohttp/hdrs.py, a repository source file, to collect header constants. This is a build-time code generator reading a local project file, not attacker-controlled input, though exec of source is a pattern worth noting.

  33. info warn → info by review dynamic-execution tools/gen.py:18:5

    `exec` called on a non-literal expression (ast pass, confidence 0.70)

        globs = {}
        exec(code, globs)
        headers = [val for val in globs.values() if isinstance(val, multidict.istr)]
        return sorted(headers)
    likely benign LLM, confidence 0.90 Executes the compiled hdrs.py namespace to gather istr header values.
    Reasoning

    Same generator script executing the trusted local hdrs.py source; the exec is part of a legitimate code-generation step with no network or encoded payload.

Reproduce This Scan

Run disclude locally to verify. Add --format sarif for SARIF output. Add --llm (with an API key in the environment) to include the LLM review.

cargo install disclude --version 4.1.0
git clone https://github.com/aio-libs/aiohttp aiohttp && cd aiohttp
git checkout v3.14.5
disclude scan --severity info --diff v3.14.4 .