PyPI / tornado / 6.6

tornado 6.6

Source
https://github.com/tornadoweb/tornado
Artifact scanned
tornado-6.6.tar.gz (sdist · 603.5 KB · SHA-256 34c4aa916d7f…)
Compared with
tornado-6.5.10.tar.gz (5 signals introduced since)
Files
208 scanned, 23 skipped (binary, oversized, or unrecognised)
Signals
1 critical · 0 warn · 19 info
Scan time
20.7 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 19 of 19 warn and critical signals; 18 demoted to info.
Disclude version
4.3.0
Scanned (UTC)
2026-10-23 10:15

Signals

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

  1. critical dynamic-execution setup.py:28:5

    `exec` at module scope (runs on import) on a non-literal expression (ast pass, confidence 0.80)

        ns = {}
        exec(f.read(), ns)
        version = ns["version"]
    suspicious LLM, confidence 0.60 setup.py execs a file read at runtime to extract a version string.
    Reasoning

    Module-scope exec of a file's contents into a namespace is unusual for setup.py and runs on every import of the package. A version-file reader normally parses with regex, so this is more suspicious than the usual pattern, but the file being executed is not shown and the code may just be reading its own version file.

  2. info warn → info by review decoder-decompress-payload tornado/http1connection.py:855:36 new in this release

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

                    try:
                        decompressed = self._decompressor.decompress(
                            compressed_data, self._chunk_size
                        )
    likely benign LLM, confidence 0.90 Streaming decompression of HTTP response or request body data.
    Reasoning

    Decompressing gzip or deflate data from an HTTP body with a max-length bound is the expected behaviour of an HTTP client/server library.

  3. info warn → info by review decoder-decompress-payload tornado/test/api_test.py:368:16 new in this release

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

                f.readline()  # Header lines.
            data = zlib.decompress(f.read()).decode("utf-8")
        objects = {}
        for line in data.splitlines():
    likely benign LLM, confidence 0.90 Test code decompresses a zlib-compressed test fixture.
    Reasoning

    Decompressing a fixture file in a test for parsing a test data file is routine.

  4. info warn → info by review decoder-decompress-payload tornado/test/property_test.py:385:17 new in this release

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

                self.assertEqual(
                    decompressor.decompress(compressor.compress(message)), message
                )
    likely benign LLM, confidence 0.90 Test round-trips a message through zlib/gzip compression.
    Reasoning

    A round-trip compress and decompress check in a test is a normal correctness assertion.

  5. info warn → info by review decoder-decompress-payload tornado/test/util_test.py:49:26 new in this release

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

                while chunk:
                    output = decompressor.decompress(chunk, max_length)
                    self.assertLessEqual(len(output), max_length)
                    tail = decompressor.unconsumed_tail
    likely benign LLM, confidence 0.90 Test exercises bounded streaming decompression.
    Reasoning

    Testing max_length-bounded decompression output and unconsumed_tail is a normal unit test.

  6. info warn → info by review decoder-decompress-payload tornado/util.py:98:16 new in this release

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

            # This works on cpython and pypy, but not jython.
            return zlib.decompressobj(16 + zlib.MAX_WBITS)
    
        def decompress(self, value: bytes, max_length: int = 0) -> bytes:
    likely benign LLM, confidence 0.90 Returns a zlib decompressobj for gzip-wrapped streams.
    Reasoning

    Creating a decompressobj with gzip-wrapper window bits is a standard compatibility shim for decompressing gzip data.

  7. info warn → info by review dynamic-execution docs/guide/security.rst:361:22

    [markup prose] `eval` called on a string literal (ast pass, confidence 0.85)

                callback(eval("(" + response + ")"));
    dismissed LLM, confidence 0.90 A documentation example showing eval applied to a string literal.
    Reasoning

    The eval call sits in reStructuredText prose as an illustrative example of a callback pattern, not executable code in the package.

  8. info critical → info by review frame-introspection tornado/options.py:266:17

    `sys._getframe` — call-stack frame introspection — file also calls `sys.exit`/`exec`/`eval` (anti-analysis shape) (ast pass, confidence 0.85)

                )
            frame = sys._getframe(0)
            if frame is not None:
                options_file = frame.f_code.co_filename
    likely benign LLM, confidence 0.85 Uses sys._getframe(0) to get the current module's filename for option definitions.
    Reasoning

    Reading the caller's frame filename to locate the options-defining file is a standard pattern for config options. The anti-analysis label comes from generic co-occurrence, not from this code.

  9. info warn → info by review dynamic-execution tornado/template.py:336:29

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

                # from being applied to the generated code.
                self.compiled = compile(
                    escape.to_unicode(self.code),
                    "%s.generated.py" % self.name.replace(".", "_"),
    likely benign LLM, confidence 0.90 Compiles generated Python code from a template.
    Reasoning

    Compiling generated template source is the core function of a template engine and the code is generated from the user's template.

  10. info warn → info by review encoding-base64 tornado/test/httpclient_test.py:238:6

    4 rows of base64-like lines, lines 238-244 (first: base64-like blob (68 bytes, compression ratio 1.16)) (raw pass, confidence 0.60)

        "y///P/gnAOKxQCD3/o///3/wTwDEYRGA7v0f////4J8AiMMCAN37P/7//8E/ARCHBQC6"
        "93/8//+DfwIgDgsAdO//+P//B/8EQBwWAOje//H//w/+CYA4LADQvf/j//8f/BMAcVgA"
        "oHv/x///P/gnAOKwAED3/o///3/wTwDEYQGA7v0f////4J8AiMMCAN37P/7//8E/ARCH"
        "BQC693/8//+DfwIgDgsAdO//+P//B/8EQBwWAOje//H//w/+CYA4LADQvf/j//8f/BMA"
    likely benign LLM, confidence 0.80 Multi-line base64 test blob, likely compressed fixture data.
    Reasoning

    Raw-pass base64-like rows of compressed test data inside a test file are consistent with fixture payloads for compression tests, and raw findings have a higher false-positive rate.

  11. info unicode-mixed-script tornado/test/httpclient_test.py:545:72

    identifier `səcrət` mixes scripts: Latin + Other (in string/comment) (raw pass, confidence 0.40)

            self.assertEqual(
                self.fetch("/auth", auth_username=username, auth_password="səcrət").body,
                b"Basic am9zw6k6c8mZY3LJmXQ=",
            )
  12. info warn → info by review frame-introspection tornado/test/options_test.py:163:17

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

    
            frame = sys._getframe(0)
            this_file = frame.f_code.co_filename
            self.assertEqual({"b_group", "", this_file}, options.groups())
    likely benign LLM, confidence 0.90 Test uses sys._getframe to get its own filename.
    Reasoning

    Retrieving the current file path inside a test to check option group membership is benign.

  13. info warn → info by review dynamic-execution tornado/test/util.py:139:5

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

        local_namespace: dict[str, typing.Any] = {}
        exec(textwrap.dedent(s), global_namespace, local_namespace)
        return local_namespace
    likely benign LLM, confidence 0.85 Test helper that executes a code string in a local namespace.
    Reasoning

    This helper execs a dedented test code string with explicit namespaces, a common pattern for testing code snippets in a test suite.

  14. info critical → info by review dynamic-import tornado/util.py:224:16

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

        if name.count(".") == 0:
            return __import__(name)
    
        parts = name.split(".")
    likely benign LLM, confidence 0.90 Dynamic import of a module name in a utility function.
    Reasoning

    This is the standard import_object helper that resolves a dotted module path supplied by the developer, a documented library feature rather than a hidden payload loader.

  15. info critical → info by review dynamic-import tornado/util.py:227:11

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

        parts = name.split(".")
        obj = __import__(".".join(parts[:-1]), fromlist=[parts[-1]])
        try:
            return getattr(obj, parts[-1])
    likely benign LLM, confidence 0.90 Dynamic __import__ of a parent module to fetch a named attribute.
    Reasoning

    Dynamic import with fromlist to resolve an attribute from a dotted path is a normal import helper pattern.

  16. info warn → info by review decoder-import-with-exec tornado/util.py:240:16

    file imports decoder module(s) zlib and calls `exec`/`eval`/`compile` — multi-stage payload shape (ast pass, confidence 0.80)

            # the string first to prevent that.
            code = compile(code, "<string>", "exec", dont_inherit=True)
        exec(code, glob, loc)
    dismissed LLM, confidence 0.85 A compatibility helper in tornado's util.py that compiles and execs source code alongside a zlib import.
    Reasoning

    The file imports zlib and calls exec/compile, but the snippet is the standard exec_in helper used for Python 2/3 compatibility in tornado. The compile call takes a source string with a fixed filename and dont_inherit, which is ordinary library behavior. The co-occurrence heuristic fires on a legitimate pattern and no encoded payload or dropper chain appears.

  17. info warn → info by review dynamic-execution tornado/util.py:240:16

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

            # the string first to prevent that.
            code = compile(code, "<string>", "exec", dont_inherit=True)
        exec(code, glob, loc)
    likely benign LLM, confidence 0.90 compile() of a caller-supplied source string inside tornado's exec_in compatibility helper.
    Reasoning

    compile() is called on a code argument inside tornado's exec_in helper, which exists to run template or module source in a supplied namespace. The source comes from the caller, not from an embedded or decoded blob, and the call is a known tornado idiom.

  18. info warn → info by review dynamic-execution tornado/util.py:241:5

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

            code = compile(code, "<string>", "exec", dont_inherit=True)
        exec(code, glob, loc)
    likely benign LLM, confidence 0.90 exec of a caller-supplied code object inside tornado's exec_in helper.
    Reasoning

    exec(code, glob, loc) is the second half of tornado's exec_in helper, which runs source passed in by the library's own callers with explicit globals and locals. The non-literal argument is expected for this function's purpose and the snippet shows no decoding or network activity.

  19. info warn → info by review frame-introspection tornado/web.py:1149:21

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

            if not template_path:
                frame = sys._getframe(0)
                web_file = frame.f_code.co_filename
                while frame.f_code.co_filename == web_file and frame.f_back is not None:
    likely benign LLM, confidence 0.92 Stack-frame walk in tornado's web.py to find the module directory for default template path resolution.
    Reasoning

    sys._getframe(0) is used to walk the stack and locate the directory of tornado/web.py when no template_path is set, so templates resolve relative to the calling application. This is a documented, legitimate use of frame introspection in a web framework.

  20. info warn → info by review decoder-decompress-payload tornado/websocket.py:825:16

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

        def _create_decompressor(self) -> "_Decompressor":
            return zlib.decompressobj(-self._max_wbits)
    
        def decompress(self, data: bytes) -> bytes:
    dismissed LLM, confidence 0.93 WebSocket permessage-deflate decompressor wrapper in tornado's websocket module.
    Reasoning

    The code creates a zlib decompressobj with negative wbits for the WebSocket permessage-deflate extension (RFC 7692) and exposes a decompress method. Data is the wire payload from the peer, not an embedded blob, so this is ordinary protocol compression.

Reproduce This Scan

Run disclude locally to verify. These commands scan the published file; the "new in this release" marks come from comparing it with the previous release's file, which they don't repeat. 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.3.0
curl -fsSL -o tornado-6.6.tar.gz https://files.pythonhosted.org/packages/d0/02/5f549b1ad5da6267ed1e1fac2eef69257b1979cc812497002499b7895ff9/tornado-6.6.tar.gz
printf '%s  %s\n' 34c4aa916d7f2b2d5cadee2c6850f5a4a7f3d688cbf58399ea9bd3057af4abd5 tornado-6.6.tar.gz | shasum -a 256 -c -
mkdir pkg && tar -xzf tornado-6.6.tar.gz -C pkg --strip-components 1
disclude scan --untrusted --severity info pkg