PyPI / wrapt / 2.5.0

wrapt 2.5.0

Source
https://github.com/GrahamDumpleton/wrapt
Tag scanned
2.5.0
Compared with
2.4.1 (0 signals introduced since)
Files
166 scanned, 47 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 26 info
Scan time
21.9 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 26 of 26 warn and critical signals; 26 demoted to info.
Disclude version
4.0.0
Scanned (UTC)
2026-10-14 18:20

Signals

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

  1. info warn → info by review frame-introspection blog/09-performance-overhead-of-using-decorators.md:103:1

    [embedded python] `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

    
    sys.setprofile(tracer)
    
    function()
    likely benign LLM, confidence 0.90 Blog example that installs a profiling tracer to measure decorator call overhead.
    Reasoning

    Markdown blog post showing sys.setprofile(tracer) as an illustration of profiling overhead for decorators. Pedagogical code in a tutorial, not an executed payload.

  2. info warn → info by review frame-introspection blog/10-performance-overhead-when-applying-decorators-to-methods.md:90:1

    [embedded python] `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

    
    sys.setprofile(tracer)
    
    instance.method()
    likely benign LLM, confidence 0.90 Blog example using sys.setprofile to trace method-call overhead.
    Reasoning

    Same tutorial pattern as the sibling post: a sys.setprofile tracer demonstration in a markdown code block around instance.method(). Educational content.

  3. info critical → info by review dynamic-import blog/13-ordering-issues-when-monkey-patching-in-python.md:105:9

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

        def _load_and_execute(target_module):
            __import__(name)
            patch_module = sys.modules[name]
            getattr(patch_module, 'apply_patch')(target_module)
    likely benign LLM, confidence 0.85 Blog example that dynamically imports a patch module by name and applies a function from it.
    Reasoning

    Illustrative monkey-patching snippet in a blog post. The __import__(name) call is on a variable, but it loads a patch module by name in a demonstration of import ordering, not a dropper. The critical severity reflects the pattern, not the context.

  4. info critical → info by review dynamic-execution docs/conf.py:55:9

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

        if isinstance(node, ast.FunctionDef) and node.name == "_format_version":
            exec(compile(ast.Module(body=[node], type_ignores=[]), "<v>", "exec"), _ns)
        elif isinstance(node, ast.Assign) and any(
            getattr(t, "id", None) in ("__version_info__", "__version__")
    likely benign LLM, confidence 0.90 Docs config extracts version definitions from source via AST and execs the selected nodes.
    Reasoning

    Sphinx docs config parses the package's own source with ast, filters for the _format_version function and version assignments, then compiles and execs only those nodes into a namespace. This is a common technique to read the version without importing the package. The source is the project's own file, so there is no external input.

  5. info critical → info by review dynamic-execution docs/conf.py:55:14

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

        if isinstance(node, ast.FunctionDef) and node.name == "_format_version":
            exec(compile(ast.Module(body=[node], type_ignores=[]), "<v>", "exec"), _ns)
        elif isinstance(node, ast.Assign) and any(
            getattr(t, "id", None) in ("__version_info__", "__version__")
    likely benign LLM, confidence 0.90 compile() of AST nodes extracted from the project's own source for version parsing.
    Reasoning

    The compile call is part of the same AST-filtering exec pattern on the project's own module node. It builds code from a parsed local source tree, not attacker-supplied data.

  6. info critical → info by review dynamic-execution docs/conf.py:60:9

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

        ):
            exec(compile(ast.Module(body=[node], type_ignores=[]), "<v>", "exec"), _ns)
    
    version_info = _ns["__version_info__"]
    likely benign LLM, confidence 0.90 Execs a version-related AST node to populate version_info in the docs config.
    Reasoning

    Second exec of the filtered AST node in the same version-extraction routine. Behavior is consistent with a benign, self-contained version reader.

  7. info critical → info by review dynamic-execution docs/conf.py:60:14

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

        ):
            exec(compile(ast.Module(body=[node], type_ignores=[]), "<v>", "exec"), _ns)
    
    version_info = _ns["__version_info__"]
    likely benign LLM, confidence 0.90 compile() of a version-related AST node in the docs configuration.
    Reasoning

    The compile feeding that exec is from the same benign version-extraction logic operating on local source.

  8. info warn → info by review dynamic-attribute src/wrapt/patches.py:103:32

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

                        if attribute in vars(cls):
                            return vars(cls)[attribute]
                    else:
                        return getattr(parent, attribute)
    likely benign LLM, confidence 0.90 Attribute lookup via vars(cls) in wrapt's path resolution logic.
    Reasoning

    wrapt library code that resolves attributes by name through vars(cls) while walking the MRO, mirroring normal Python attribute lookup. This is standard introspection for a proxy/patching library.

  9. info warn → info by review dynamic-attribute src/wrapt/patches.py:348:13

    reach-by-name through `vars.get` (ast pass, confidence 0.60)

        parent = resolve_path(module, path)[2]
        prior = vars(parent).get(attribute, MISSING)
        wrapper = AttributeWrapper(prior, attribute, factory, args, kwargs)
        apply_patch(parent, attribute, wrapper)
    likely benign LLM, confidence 0.90 Reads the existing attribute from a parent object so wrapt can wrap it.
    Reasoning

    vars(parent).get(attribute, MISSING) reads the prior attribute so a wrapper can be applied. This is the intended function-patching mechanism of wrapt, not hidden access.

  10. info warn → info by review dynamic-attribute src/wrapt/patches.py:840:17

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

                (
                    vars(cls)[attribute]
                    for cls in inspect.getmro(owner)[1:]
                    if attribute in vars(cls)
    likely benign LLM, confidence 0.90 MRO walk through vars(cls) to locate an attribute for wrapping.
    Reasoning

    Generator walking the MRO with vars(cls) to find the original attribute, consistent with wrapt's documented patching behavior.

  11. info critical → info by review dynamic-import src/wrapt/proxies.py:363:18

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

        def _import():
            module = __import__(name, fromlist=[""])
    
            if attribute is not None:
    likely benign LLM, confidence 0.85 Lazy-import helper in wrapt that imports a module by name on first use.
    Reasoning

    wrapt's lazy import helper calls __import__ on a module name stored in the lazy-import proxy, deferring import until first attribute access. The name comes from library configuration, not untrusted input, so this is an expected pattern.

  12. info critical → info by review dynamic-execution tests/core/test_adapter.py:18:1

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

    decorators = types.ModuleType("decorators")
    exec(DECORATORS_CODE, decorators.__dict__, decorators.__dict__)
    likely benign LLM, confidence 0.80 Test code that execs a constant source string into a fake decorators module.
    Reasoning

    Test fixture builds a module object and execs a DECORATORS_CODE string into its namespace to exercise the adapter. The exec source is a constant defined in the test file, so it is not external input. Confidence is somewhat lower because the constant itself is not shown.

  13. info critical → info by review dynamic-execution tests/core/test_adapter_annotations.py:26:1

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

    decorators = types.ModuleType("decorators")
    exec(DECORATORS_CODE, decorators.__dict__, decorators.__dict__)
    likely benign LLM, confidence 0.85 Test fixture that execs a constant code string into a throwaway module to build decorator helpers.
    Reasoning

    The exec runs a constant named DECORATORS_CODE into a fresh ModuleType's namespace inside a test file. This is a common test-fixture pattern for building decorator helpers, and the snippet shows no network, shell, or encoded payload. The definition of DECORATORS_CODE is not shown, which leaves some doubt.

  14. info critical → info by review dynamic-execution tests/core/test_adapter_kwonly.py:18:1

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

    decorators = types.ModuleType("decorators")
    exec(DECORATORS_CODE, decorators.__dict__, decorators.__dict__)
    likely benign LLM, confidence 0.85 Test module that execs a local decorators code constant into a temporary module namespace.
    Reasoning

    Same DECORATORS_CODE exec into a temporary ModuleType in a test module. The pattern matches test scaffolding for wrapper behaviour. Nothing in the snippet indicates a payload or obfuscated intent.

  15. info critical → info by review dynamic-execution tests/core/test_class.py:16:1

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

    decorators = types.ModuleType("decorators")
    exec(DECORATORS_CODE, decorators.__dict__, decorators.__dict__)
    likely benign LLM, confidence 0.85 Test file that builds a decorators module by exec-ing a constant code string.
    Reasoning

    Module-level exec of DECORATORS_CODE into a ModuleType in a test file. This is test scaffolding for generating decorators, consistent with the rest of the suite. No malicious indicators appear in the snippet.

  16. info critical → info by review dynamic-import tests/core/test_find_wrapper.py:90:27

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

    
            wrapt.apply_patch(__import__(__name__), "function_closure", their_closure)
    
            current = wrapt.resolve_path(__name__, "function_closure")[2]
    likely benign LLM, confidence 0.85 Test calls __import__(__name__) to obtain its own module object for patching.
    Reasoning

    __import__ is called on __name__, which resolves to the current test module itself. This is a self-reference used to pass the module to wrapt.apply_patch. The argument is not attacker-controlled input.

  17. info critical → info by review dynamic-import tests/core/test_find_wrapper.py:219:27

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

    
            wrapt.apply_patch(__import__(__name__), "function_replaced", original)
    
            current = wrapt.resolve_path(__name__, "function_replaced")[2]
    likely benign LLM, confidence 0.85 Test uses __import__(__name__) to get its own module for a patch operation.
    Reasoning

    Same __import__(__name__) self-reference pattern used to supply the current module to wrapt.apply_patch in a test. No external or dynamic module name is involved.

  18. info critical → info by review dynamic-execution tests/core/test_function.py:16:1

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

    decorators = types.ModuleType("decorators")
    exec(DECORATORS_CODE, decorators.__dict__, decorators.__dict__)
    likely benign LLM, confidence 0.85 Function test file that execs a decorators code constant into a temporary module.
    Reasoning

    Module-level exec of the DECORATORS_CODE constant into a temporary module in a test file, a standard fixture pattern. The snippet shows no evidence of malicious behaviour.

  19. info critical → info by review dynamic-execution tests/core/test_inner_classmethod.py:16:1

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

    decorators = types.ModuleType("decorators")
    exec(DECORATORS_CODE, decorators.__dict__, decorators.__dict__)
    likely benign LLM, confidence 0.85 Classmethod test that execs a decorators code constant into a temporary module.
    Reasoning

    Module-level exec of DECORATORS_CODE into a ModuleType in a test module. This is consistent with test scaffolding for classmethod wrapping and has no sign of a payload.

  20. info critical → info by review dynamic-execution tests/core/test_inner_staticmethod.py:16:1

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

    decorators = types.ModuleType("decorators")
    exec(DECORATORS_CODE, decorators.__dict__, decorators.__dict__)
    likely benign LLM, confidence 0.85 Staticmethod test that execs a decorators code constant into a temporary module.
    Reasoning

    Module-level exec of the DECORATORS_CODE constant into a temporary module in a staticmethod test. Standard test scaffolding with no malicious indicators in the snippet.

  21. info critical → info by review dynamic-execution tests/core/test_instancemethod.py:16:1

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

    decorators = types.ModuleType("decorators")
    exec(DECORATORS_CODE, decorators.__dict__, decorators.__dict__)
    likely benign LLM, confidence 0.85 Instancemethod test that execs a decorators code constant into a temporary module.
    Reasoning

    DECORATORS_CODE is exec'd into a fresh module in an instancemethod test. This is the usual fixture pattern for generating decorators in wrapt's test suite.

  22. info critical → info by review dynamic-execution tests/core/test_nested_function.py:16:1

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

    decorators = types.ModuleType("decorators")
    exec(DECORATORS_CODE, decorators.__dict__, decorators.__dict__)
    likely benign LLM, confidence 0.85 Nested-function test that execs a decorators code constant into a temporary module.
    Reasoning

    Module-level exec of DECORATORS_CODE into a temporary ModuleType in a nested-function test. Fits test scaffolding and shows no payload or obfuscation.

  23. info critical → info by review dynamic-execution tests/core/test_object_proxy.py:23:1

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

    objects = types.ModuleType("objects")
    exec(OBJECTS_CODE, objects.__dict__, objects.__dict__)
    likely benign LLM, confidence 0.85 Object proxy test that execs an objects code constant into a temporary module.
    Reasoning

    Module-level exec of the OBJECTS_CODE constant into a temporary objects module, a standard test fixture for object proxy behaviour. No indicators of malicious intent are visible.

  24. info critical → info by review dynamic-execution tests/core/test_outer_classmethod.py:18:1

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

    decorators = types.ModuleType("decorators")
    exec(DECORATORS_CODE, decorators.__dict__, decorators.__dict__)
    likely benign LLM, confidence 0.85 Outer-classmethod test that execs a decorators code constant into a temporary module.
    Reasoning

    Module-level exec of DECORATORS_CODE into a ModuleType in an outer-classmethod test. This is test scaffolding with no visible malicious behaviour.

  25. info critical → info by review dynamic-execution tests/core/test_outer_staticmethod.py:16:1

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

    decorators = types.ModuleType("decorators")
    exec(DECORATORS_CODE, decorators.__dict__, decorators.__dict__)
    likely benign LLM, confidence 0.85 Outer-staticmethod test that execs a decorators code constant into a temporary module.
    Reasoning

    Module-level exec of DECORATORS_CODE into a temporary module in an outer-staticmethod test. Standard fixture pattern with nothing suspicious in the snippet.

  26. info critical → info by review dynamic-execution tests/core/test_type_module_attribute.py:31:1

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

    objects = types.ModuleType("objects")
    exec(OBJECTS_CODE, objects.__dict__, objects.__dict__)
    likely benign LLM, confidence 0.80 A test file execs a constant code string into a synthetic ModuleType's namespace at module scope.
    Reasoning

    The snippet builds a fresh types.ModuleType and execs OBJECTS_CODE into its __dict__. This is a common test-fixture pattern for populating a synthetic module, and the file is under tests/core with a name that matches a module-attribute test. OBJECTS_CODE is presumably a hardcoded constant in the same file, which the snippet doesn't show. The exec runs on import and takes a non-literal, so it is worth noting, but nothing here shows attacker-controlled input, network access, or a dropper pipeline. The exec is confined to a throwaway module object.

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.0.0
git clone https://github.com/GrahamDumpleton/wrapt wrapt && cd wrapt
git checkout 2.5.0
disclude scan --severity info --diff 2.4.1 .