PyPI / werkzeug / 3.1.9

werkzeug 3.1.9

Source
https://github.com/pallets/werkzeug
Tag scanned
3.1.9
Compared with
3.1.8 (0 signals introduced since)
Files
229 scanned, 46 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 6 info
Scan time
7.5 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 6 of 6 warn and critical signals; 6 demoted to info.
Disclude version
4.1.0
Scanned (UTC)
2026-10-22 04:00

Signals

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

  1. info warn → info by review dynamic-execution src/werkzeug/debug/console.py:177:13

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

            try:
                exec(code, self.locals)
            except Exception:
                self.showtraceback()
    likely benign LLM, confidence 0.90 exec of user-entered code in the Werkzeug debugger's interactive console.
    Reasoning

    This exec runs code entered into the Werkzeug interactive debugger console against the frame's locals. That is the documented purpose of the debugger, which is gated by a PIN and is only meant for development. The pattern is dynamic execution, but it is a visible, intended feature rather than hidden obfuscation or a dropper.

  2. info warn → info by review frame-introspection src/werkzeug/debug/repr.py:49:30

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

        if obj is missing:
            rv = gen.dump_locals(sys._getframe(1).f_locals)
        else:
            rv = gen.dump_object(obj)
    likely benign LLM, confidence 0.90 Reads the caller's frame locals to render them in the debugger's dump output.
    Reasoning

    sys._getframe(1).f_locals is read to dump local variables for the debugger's object-inspection output. It is a plain, expected use of frame introspection in a debugging helper, with no exfiltration or hidden behavior visible.

  3. info warn → info by review dynamic-execution src/werkzeug/routing/rules.py:736:9

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

            locs: dict[str, t.Any] = {}
            exec(code, globs, locs)
            return locs[name]  # type: ignore
    likely benign LLM, confidence 0.85 exec of internally generated code to build a routing converter function.
    Reasoning

    This exec runs a code object that the routing module generates from its own internal template (the converter function built from rule definitions). The inputs are library-controlled, not attacker-supplied network or file data, and the result is simply looked up by name. This is a known code-generation technique in routing.

  4. info warn → info by review dynamic-execution src/werkzeug/routing/rules.py:836:16

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

    
            code = compile(module, "<werkzeug routing>", "exec")
            return self._get_func_code(code, func_ast.name)
    likely benign LLM, confidence 0.88 compile of an internally generated AST module for the routing code generator.
    Reasoning

    compile is applied to a module AST built by the routing code generator, using a fixed filename of '<werkzeug routing>'. It is part of the same internal codegen path as the exec above. The source is not external input, so there is no sign of malicious intent.

  5. info critical → info by review dynamic-import src/werkzeug/utils.py:589:13

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

            try:
                __import__(import_name)
            except ImportError:
                if "." not in import_name:
    likely benign LLM, confidence 0.90 Dynamic import inside werkzeug's import_string utility, which loads modules by dotted name.
    Reasoning

    This __import__ is inside import_string, a standard helper that imports a module from a dotted name supplied by the calling developer. The call is the normal way this utility works, so the 'critical' severity reflects the generic dynamic-import signal and not real malicious behavior.

  6. info critical → info by review dynamic-import src/werkzeug/utils.py:597:18

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

            module_name, obj_name = import_name.rsplit(".", 1)
            module = __import__(module_name, globals(), locals(), [obj_name])
            try:
                return getattr(module, obj_name)
    likely benign LLM, confidence 0.90 Dynamic __import__ of a module split from a dotted path, followed by getattr to resolve an object.
    Reasoning

    This __import__ call uses a module name split from a dotted import path in import_string, followed by getattr on the result. It is the standard fallback that resolves an object from a dotted path. The pattern is an ordinary dynamic-import idiom in a library helper.

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/pallets/werkzeug werkzeug && cd werkzeug
git checkout 3.1.9
disclude scan --severity info --diff 3.1.8 .