PyPI / dill / 0.4.1

dill 0.4.1

Source
https://github.com/uqfoundation/dill
Tag scanned
0.4.1
Compared with
0.4.0 (0 signals introduced since)
Files
56 scanned, 9 skipped (binary, oversized, or unrecognised)
Signals
1 critical · 2 warn · 46 info
Scan time
39.4 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 49 of 49 warn and critical signals; 46 demoted to info.
Disclude version
4.0.0
Scanned (UTC)
2026-10-14 18:49

Signals

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

  1. critical dynamic-execution scripts/get_gprof:63:15

    `os.system` called on a non-literal command — runtime-determined shell invocation (ast pass, confidence 0.85)

        try:
            res = os.system(msg)
        except Exception:
            print ("Please verify install of 'gprof2dot' to view profile graphs")
    likely benign LLM, confidence 0.65 Profiling script shells out to gprof2dot and dot to render a profile graph.
    Reasoning

    os.system runs a command string built at runtime, which is a shell-injection risk if file names are untrusted. The surrounding code is a legitimate gprof2dot/dot pipeline with a helpful error message, so it looks like a robustness issue rather than a dropper or malicious payload.

  2. warn dynamic-execution scripts/get_gprof:43:9

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

        for line in obj[:-1]:
            exec(line)
        # one-line generation of an instance
        try:
    likely benign LLM, confidence 0.60 Developer profiling script execs reconstructed instance-generation lines from its own data.
    Reasoning

    The exec runs lines from a developer-facing profiling script that rebuilds object instances from its own generated output. Executing data from a file is a code-quality and trust concern if the input is untrusted, but there is no sign of malicious intent or obfuscation.

  3. warn dynamic-execution scripts/get_gprof:46:15

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

        try:
            obj = eval(obj[-1])
        except Exception:
            print ("Error processing object instance")
    likely benign LLM, confidence 0.60 Profiling script evals a generated instance expression from its own data file.
    Reasoning

    eval is applied to the last line of profile-derived object data in a try block. This is unsafe if the profile input is attacker-controlled, but in context it reads as a utility parsing its own output, with no malicious indicators.

  4. info critical → info by review dynamic-import dill/__diff.py:220:11

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

        before = set(sys.modules.keys())
        mod = __import__(*args, **kwds)
        after = set(sys.modules.keys()).difference(before)
        for m in after:
    likely benign LLM, confidence 0.85 Forwarding wrapper around __import__ that diffs sys.modules to track newly imported modules.
    Reasoning

    This is a pass-through wrapper around __import__ that records which modules a call newly loads, a common pattern for dill's module tracking. The arguments come from the caller, not attacker-controlled data, and the file is an established serialization library.

  5. info critical → info by review builtins-write dill/__diff.py:226:1

    `builtins.__import__ = ...` — patches a built-in for every importer of this module (ast pass, confidence 0.95)

    
    builtins.__import__ = _imp
    if hasattr(builtins, "_"):
        del builtins._
    likely benign LLM, confidence 0.80 Temporarily swaps builtins.__import__ with a tracking wrapper and restores state afterward.
    Reasoning

    The builtins.__import__ replacement is the temporary hook paired with the wrapper above, and the snippet shows cleanup of the builtins._ name. The patch is scoped to module-tracking, not to a payload or persistence mechanism.

  6. info critical → info by review frame-introspection dill/_dill.py:213:31

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

                # Use the calling frame's module
                self.__module__ = inspect.currentframe().f_back.f_globals['__name__']
            else:
                self.__module__ = module_name # pragma: no cover
    likely benign LLM, confidence 0.90 Uses inspect.currentframe to read the caller's module name for an object's __module__ attribute.
    Reasoning

    Reading the calling frame's __name__ to set a pickled object's __module__ is a standard technique for determining the caller's module. The sys.exit/exec co-occurrence is a broad heuristic that does not fit this use.

  7. info warn → info by review dynamic-execution dill/_dill.py:596:12

    `marshal.loads` deserializes Python bytecode from bytes — code-object sink (ast pass, confidence 0.75)

    def _unmarshal(string):
        return marshal.loads(string)
    
    def _load_type(name):
    likely benign LLM, confidence 0.85 Wrapper around marshal.loads used to rebuild serialized code objects.
    Reasoning

    dill's core job is serializing code objects, and marshal is the standard way to do that. The function deserializes data the library itself produced, so this is expected behavior for a pickler rather than a hidden dropper.

  8. info warn → info by review decoder-import-with-exec dill/_dill.py:980:12

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

    def _eval_repr(repr_str):
        return eval(repr_str)
    
    def _create_array(f, args, state, npdict=None):
    likely benign LLM, confidence 0.80 Evaluates a repr string to reconstruct a serialized object during unpickling.
    Reasoning

    _eval_repr evaluates repr strings produced during serialization, such as numpy dtype descriptions. The eval is a known weak point in deserialization, but the input is data dill wrote itself and the file is a serializer, not a loader for untrusted payloads.

  9. info warn → info by review dynamic-execution dill/_dill.py:980:12

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

    def _eval_repr(repr_str):
        return eval(repr_str)
    
    def _create_array(f, args, state, npdict=None):
    likely benign LLM, confidence 0.75 Eval of a repr string used to rebuild a serialized object.
    Reasoning

    This is the eval finding for the same function as the one above. It is a legitimate reconstruction path, though eval on serialized input deserves a note.

  10. info critical → info by review dynamic-import dill/_dill.py:1012:26

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

                try:
                    module = __import__(names[0])
                except ImportError:
                    pass
    likely benign LLM, confidence 0.80 Dynamic __import__ of a module name recovered from pickled data, guarded by ImportError handling.
    Reasoning

    Importing a module by name taken from serialized data is how unpickling locates classes and functions. The import is guarded by an ImportError handler, which is consistent with normal loader behavior.

  11. info critical → info by review dynamic-execution dill/_dill.py:1038:16

    `eval` called on a constructed string (ast pass, confidence 0.80)

            attr = repr_str.split("'")[3]
            return eval(attr+'.__dict__["'+name+'"]')
        except Exception:
            try:
    likely benign LLM, confidence 0.70 Evaluates a constructed dotted-path expression to resolve an attribute from a repr.
    Reasoning

    The eval builds an attribute-access expression from a repr string to locate an object by its qualified name. Its input comes from serialized data, so it is a known risk in deserialization code, but it reads as a lookup routine rather than an injected payload.

  12. info critical → info by review dynamic-import dill/_dill.py:1065:33

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

                obj = items[-1]
                submodule = getattr(__import__(module, None, None, [obj]), obj)
                if isinstance(submodule, (ModuleType, type)):
                    return submodule
    likely benign LLM, confidence 0.85 Dynamic __import__ used to resolve dotted module and attribute paths when loading objects.
    Reasoning

    This is the standard _import_module helper, which resolves dotted names and imports submodules with __import__. Its use is consistent with the library's purpose.

  13. info critical → info by review dynamic-import dill/_dill.py:1068:20

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

                    return submodule
                return __import__(import_name, None, None, [obj])
            else:
                return __import__(import_name)
    likely benign LLM, confidence 0.85 Fallback __import__ inside the module-resolution helper.
    Reasoning

    This is the fallback branch of the same module-resolution helper. The import name derives from the object being unpickled, which is the expected behavior.

  14. info critical → info by review dynamic-import dill/_dill.py:1070:20

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

            else:
                return __import__(import_name)
        except (ImportError, AttributeError, KeyError):
            if safe:
    likely benign LLM, confidence 0.85 Final __import__ in the module-resolution helper, wrapped in exception handling.
    Reasoning

    This is the final import in the same resolver, with ImportError, AttributeError and KeyError caught, which fits a best-effort loader.

  15. info warn → info by review decoder-import-with-exec dill/_objects.py:239:17

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

    # types module (part of CH 8)
    a['CodeType'] = compile('','','exec')
    a['DictProxyType'] = type.__dict__
    a['DictProxyType2'] = _newclass.__dict__
    likely benign LLM, confidence 0.90 Builds an empty code object to capture the CodeType type for a registry of built-in types.
    Reasoning

    compile('','','exec') creates an empty code object solely to obtain the CodeType type for a lookup table of Python internal types. It executes nothing.

  16. info warn → info by review decoder-decompress-payload dill/_objects.py:460:27

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

    x['ZlibCompressType'] = zlib.compressobj()
    x['ZlibDecompressType'] = zlib.decompressobj()
    # file formats (CH 13)
    x['CSVReaderType'] = csv.reader(_cstrI)
    likely benign LLM, confidence 0.90 Instantiates zlib compressor/decompressor objects to record their types in a registry.
    Reasoning

    zlib.decompressobj() here creates a type reference for a table of standard library types, not a runtime payload. Nothing is decompressed from embedded data.

  17. info warn → info by review dynamic-attribute dill/_shims.py:174:12

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

        """
        func = globals().get(name)
        if func is not None:
            _dill.__dict__[name] = func
    likely benign LLM, confidence 0.90 Looks up a function by name in module globals and assigns it into the dill module dict.
    Reasoning

    globals().get(name) to pull a function from module globals and copy it into the dill namespace is a normal dynamic lookup pattern in a serialization library's shim module; no sign of malicious payload.

  18. info critical → info by review dynamic-execution dill/objtypes.py:18:5

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

    for _type in objects.keys():
        exec("%s = type(objects['%s'])" % (_type,_type))
        
    del objects
    likely benign LLM, confidence 0.80 Module-level exec generates type alias names from a static internal dict of object types.
    Reasoning

    exec runs at import time, but the string is built from keys of a fixed internal objects dict to create type aliases (e.g. FunctionType = type(objects['FunctionType'])). The expression is non-literal but derived from trusted internal constants, so it is a benign if unusual metaprogramming idiom.

  19. info warn → info by review frame-introspection dill/pointers.py:93:19

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

        ignore.add(id(ignore))
        ignore.add(id(sys._getframe()))  # this function
        ignore.add(id(sys._getframe(1))) # find_chain/find_backref_chain, likely
        gc.collect()
    likely benign LLM, confidence 0.90 Uses sys._getframe to add the current frame's id to an ignore set during backref search.
    Reasoning

    sys._getframe is used with an explicit comment to exclude helper frames from a reference-chain search during garbage-collection-based object tracing; standard debugging/introspection in dill.

  20. info warn → info by review frame-introspection dill/pointers.py:94:19

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

        ignore.add(id(sys._getframe()))  # this function
        ignore.add(id(sys._getframe(1))) # find_chain/find_backref_chain, likely
        gc.collect()
        while queue:
    likely benign LLM, confidence 0.90 Uses sys._getframe(1) to exclude the caller frame from backreference chain search.
    Reasoning

    Same benign pattern: sys._getframe(1) is used with a comment to exclude the caller's frame from object-graph traversal.

  21. info critical → info by review dynamic-import dill/session.py:125:42

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

            for modname, name in main_module.__dict__.pop('__dill_imported_top_level'):
                main_module.__dict__[name] = __import__(modname)
        except KeyError:
            pass
    likely benign LLM, confidence 0.85 Re-imports top-level modules recorded in the session's __dill_imported_top_level metadata.
    Reasoning

    __import__ on modname taken from a session-stored list of previously imported top-level modules; restores imports when loading a session. It is dynamic but operates on the module's own recorded names, not attacker-controlled execution. Loading untrusted session files is a genuine risk, but the code itself is ordinary restoration logic.

  22. info warn → info by review dynamic-attribute dill/session.py:226:16

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

                warnings.warn(message + ".", PendingDeprecationWarning)
                if locals()[par]:  # the defaults are None and False
                    raise TypeError("both %r and %r arguments were used" % (par, old_par))
        refimported = kwds.pop('byref', refimported)
    likely benign LLM, confidence 0.90 Reads a parameter value from locals() to check for conflicting deprecated arguments.
    Reasoning

    locals()[par] reads a keyword-argument flag by name inside a deprecation-handling helper; ordinary Python introspection with no malicious characteristics.

  23. info warn → info by review dynamic-attribute dill/session.py:611:26

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

    ):
        setattr(_dill, name, globals()[name])
    del name
    likely benign LLM, confidence 0.90 Re-exports globals into the _dill module namespace by name.
    Reasoning

    Copies names from globals() onto the _dill module in a loop, a standard re-export pattern for aliasing module attributes.

  24. info warn → info by review dynamic-execution dill/source.py:60:13

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

        try: #FIXME: unsafe
            _ = eval("lambda %s : %s" % (lhs,rhs), globals(),locals())
        except Exception: _ = dummy
        # get code objects, for comparison
    likely benign LLM, confidence 0.85 Evaluates a reconstructed lambda expression to compare code objects during source introspection.
    Reasoning

    eval of a lambda built from source-extracted lhs/rhs strings, used to recover code objects for comparison while reconstructing source; the FIXME acknowledges unsafety but inputs come from the local source being inspected, not untrusted remote data.

  25. info warn → info by review dynamic-execution dill/source.py:82:18

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

            try: #FIXME: unsafe
                _f = eval("lambda %s : %s" % (_lhs,_rhs), globals(),locals())
            except Exception: _f = dummy
            # get code objects, for comparison
    likely benign LLM, confidence 0.85 Evaluates a reconstructed lambda from parsed source to compare code objects.
    Reasoning

    Same pattern as the sibling eval: builds a lambda from parsed source text for code-object comparison, with a known FIXME; expected for a source-inspection library.

  26. info warn → info by review dynamic-execution dill/source.py:397:23

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

                    lines, lnum = ["%s = __import__('%s', fromlist=['%s']).%s\n" % (name,module,name,name)], 0
                    obj = eval(lines[0].lstrip(name + ' = '))
                    lines, lnum = getsourcelines(obj, enclosing=enclosing)
    likely benign LLM, confidence 0.85 Evaluates an import-and-attribute assignment string to retrieve an object for source retrieval.
    Reasoning

    eval of a generated assignment line that imports a module attribute to obtain an object for source lookup; operates on names from the inspected module, typical of dill's getsource machinery.

  27. info warn → info by review dynamic-execution dill/source.py:543:13

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

                # _ = eval(getsource(f, force=True)) #XXX: safer but less robust
                exec(getimportable(f, alias='_'), __globals__, __locals__)
            except Exception:
                raise ImportError('cannot import name ' + f.__name__)
    likely benign LLM, confidence 0.85 Executes generated importable source to reconstruct a named object in the given namespaces.
    Reasoning

    exec of importable source generated by dill's own getimportable from the function being pickled, to recreate a named object; dynamic but intentional library behavior on local code.

  28. info warn → info by review dynamic-execution dill/source.py:713:14

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

           #print(_str)
            try: exec(_str) #XXX: check if == obj? (name collision)
            except ImportError: #XXX: better top-down or bottom-up recursion?
                _head = head.rsplit(".",1)[0] #(or get all, then compare == obj?)
    likely benign LLM, confidence 0.85 Executes a generated import string while recursively resolving a dotted object name.
    Reasoning

    exec of a generated import/source string during recursive name resolution for module-level objects; operates on names derived from the object being handled, with an XXX note about name collisions rather than malicious intent.

  29. info warn → info by review decoder-import-with-exec dill/temp.py:71:5

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

        local = {}
        exec(source, local)
        _ = eval("%s" % alias, local)
        return _
    likely benign LLM, confidence 0.85 Legitimate exec/eval of dill-generated source in a temp-object helper.
    Reasoning

    This is dill's temp-file helper that reloads source it generated itself via dumpsource and exec/evals it to build a named object. The codecs import and exec/eval are the library's normal mechanism here, not a multi-stage payload.

  30. info warn → info by review dynamic-execution dill/temp.py:71:5

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

        local = {}
        exec(source, local)
        _ = eval("%s" % alias, local)
        return _
    likely benign LLM, confidence 0.85 exec of a non-literal source string that dill itself produced.
    Reasoning

    The exec runs source produced by dill's own dumpsource serializer inside a fresh local namespace. That is the expected dynamic-loading design of a serialization library, not attacker-supplied input.

  31. info warn → info by review dynamic-execution dill/temp.py:72:9

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

        exec(source, local)
        _ = eval("%s" % alias, local)
        return _
    likely benign LLM, confidence 0.85 eval of a formatted alias name in dill's temp-object helper.
    Reasoning

    The eval evaluates an alias name formatted into a string and looked up in the local dict populated by the prior exec. It is part of the same self-generated-source round trip.

  32. info warn → info by review dynamic-execution dill/temp.py:220:5

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

        local = {}
        exec(source, local)
        _ = eval("%s" % alias, local)
        return _
    likely benign LLM, confidence 0.85 Repeated exec of dill-generated source in a second helper.
    Reasoning

    The same exec-of-generated-source pattern recurs in a second helper in this file, consistent with dill's serialization design. The snippet shows no network, download, or obfuscated payload.

  33. info warn → info by review dynamic-execution dill/temp.py:221:9

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

        exec(source, local)
        _ = eval("%s" % alias, local)
        return _
    likely benign LLM, confidence 0.85 Repeated eval of a formatted alias in dill's second temp helper.
    Reasoning

    This is the matching eval of the alias after the second exec. It follows the same benign self-generated-source pattern as the other findings in this file.

  34. info warn → info by review frame-introspection dill/tests/test_detect.py:19:9

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

    def test_bad_things():
        f = inspect.currentframe()
        assert baditems(f) == [f]
        #assert baditems(globals()) == [f] #XXX
    likely benign LLM, confidence 0.90 Test code using inspect.currentframe to exercise dill's detection logic.
    Reasoning

    This is a unit test calling inspect.currentframe to check that baditems detects frame objects. Frame introspection is the subject under test, not a malicious technique.

  35. info warn → info by review dynamic-execution dill/tests/test_module.py:72:12

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

    def get_lambda(str, **kwarg):
        return eval(str, kwarg, None)
    
    obj = get_lambda('lambda x: math.exp(x)', math=math)
    likely benign LLM, confidence 0.90 Test helper using eval on a hardcoded lambda string.
    Reasoning

    This test helper evaluates a fixed lambda string with a supplied math namespace to check serialization of lambdas. The input is a controlled literal from the test, not external data.

  36. info warn → info by review dynamic-attribute dill/tests/test_session.py:42:24

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

                for obj in ('json', 'url', 'local_mod', 'sax', 'dom'):
                    assert globals()[obj].__name__ in sys.modules
                assert 'calendar' in sys.modules and 'cmath' in sys.modules
                import calendar, cmath
    likely benign LLM, confidence 0.92 Test reading module globals by name to verify session restoration.
    Reasoning

    The test looks up module names through globals() to verify that session state was restored after dill round-trip. This is ordinary test assertion code.

  37. info warn → info by review dynamic-attribute dill/tests/test_session.py:47:24

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

                for obj in ('Calendar', 'isleap'):
                    assert globals()[obj] is sys.modules['calendar'].__dict__[obj]
                assert __main__.day_name.__module__ == 'calendar'
                if refimported:
    likely benign LLM, confidence 0.92 Test reading calendar globals by name to check session state.
    Reasoning

    The globals() lookup checks that calendar attributes are present after session load. It is a standard verification step in a serialization test.

  38. info warn → info by review dynamic-attribute dill/tests/test_session.py:126:20

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

            for obj in ('json', 'url', 'local_mod', 'sax', 'dom'):
                assert globals()[obj].__name__ == globals_copy[obj].__name__
    
            for obj in ('x', 'empty', 'names'):
    likely benign LLM, confidence 0.92 Test comparing globals against a copy after session round-trip.
    Reasoning

    The loop compares globals values against a copied namespace after a session round-trip. This is expected assertion logic with no malicious indicators.

  39. info warn → info by review dynamic-execution dill/tests/test_sources.py:118:3

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

      local = {}
      exec(ds.dumpsource(add, alias='raw'), {}, local)
      exec(ds.dumpsource(ts.add, alias='mod'), {}, local)
      assert local['raw'](1,2) == local['mod'](1,2)
    likely benign LLM, confidence 0.90 Test exec of dumpsource output for locally defined functions.
    Reasoning

    The test execs dumpsource output for functions it defines to confirm that source regeneration works. The code is test-local and self-generated.

  40. info warn → info by review dynamic-execution dill/tests/test_sources.py:119:3

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

      exec(ds.dumpsource(add, alias='raw'), {}, local)
      exec(ds.dumpsource(ts.add, alias='mod'), {}, local)
      assert local['raw'](1,2) == local['mod'](1,2)
      exec(ds.dumpsource(squared, alias='raw'), {}, local)
    likely benign LLM, confidence 0.90 Test exec of dumpsource output for a locally defined function.
    Reasoning

    This exec of generated source for a locally defined test function matches the same self-verification pattern. Nothing in the snippet is external or obfuscated.

  41. info warn → info by review dynamic-execution dill/tests/test_sources.py:121:3

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

      assert local['raw'](1,2) == local['mod'](1,2)
      exec(ds.dumpsource(squared, alias='raw'), {}, local)
      exec(ds.dumpsource(ts.squared, alias='mod'), {}, local)
      assert local['raw'](3) == local['mod'](3)
    likely benign LLM, confidence 0.90 Test exec of dumpsource output for another local test function.
    Reasoning

    This exec of dumpsource output for the squared test function is part of the same source-regeneration test. It is benign test code.

  42. info warn → info by review dynamic-execution dill/tests/test_sources.py:122:3

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

      exec(ds.dumpsource(squared, alias='raw'), {}, local)
      exec(ds.dumpsource(ts.squared, alias='mod'), {}, local)
      assert local['raw'](3) == local['mod'](3)
      assert ds._wrap(add)(1,2) == ds._wrap(ts.add)(1,2)
    likely benign LLM, confidence 0.90 Test executes source text regenerated by dill's dumpsource to check round-trip behaviour.
    Reasoning

    The exec call runs source generated by dill's own dumpsource helper inside a unit test, comparing results against the original functions. It is a self-referential round-trip test with no external input, so the dynamic execution is expected.

  43. info warn → info by review dynamic-execution dill/tests/test_sources.py:152:3

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

      local = {}
      exec(ds.getimport(add, alias='raw'), {}, local)
      exec(ds.getimport(ts.add, alias='mod'), {}, local)
      assert local['raw'](1,2) == local['mod'](1,2)
    likely benign LLM, confidence 0.90 Test execs import strings generated by dill's getimport to verify reconstructed functions.
    Reasoning

    The exec call evaluates getimport output produced by dill's own helper from test-defined functions in a test namespace. This is standard round-trip verification and is not attacker-controlled.

  44. info warn → info by review dynamic-execution dill/tests/test_sources.py:153:3

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

      exec(ds.getimport(add, alias='raw'), {}, local)
      exec(ds.getimport(ts.add, alias='mod'), {}, local)
      assert local['raw'](1,2) == local['mod'](1,2)
      exec(ds.getimport(squared, alias='raw'), {}, local)
    likely benign LLM, confidence 0.90 Test execs dill-generated getimport strings and asserts on the resulting callables.
    Reasoning

    Same pattern as the neighbouring findings: exec of dill-generated getimport strings inside a test, with assertions on the results. No external or hostile input is involved.

  45. info warn → info by review dynamic-execution dill/tests/test_sources.py:155:3

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

      assert local['raw'](1,2) == local['mod'](1,2)
      exec(ds.getimport(squared, alias='raw'), {}, local)
      exec(ds.getimport(ts.squared, alias='mod'), {}, local)
      assert local['raw'](3) == local['mod'](3)
    likely benign LLM, confidence 0.90 Test execs getimport output for squared functions and compares results.
    Reasoning

    Repeated test round-trip using dill's getimport on local functions, with exec in an isolated dict. The pattern is consistent with legitimate serialization testing.

  46. info warn → info by review dynamic-execution dill/tests/test_sources.py:156:3

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

      exec(ds.getimport(squared, alias='raw'), {}, local)
      exec(ds.getimport(ts.squared, alias='mod'), {}, local)
      assert local['raw'](3) == local['mod'](3)
      exec(ds.getimport(Bar, alias='raw'), {}, local)
    likely benign LLM, confidence 0.90 Test execs getimport output for squared and Bar to verify reconstruction.
    Reasoning

    Test code executing dill-generated import source for a function and a class, then checking behaviour. This is expected for a serialization library's test suite.

  47. info warn → info by review dynamic-execution dill/tests/test_sources.py:158:3

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

      assert local['raw'](3) == local['mod'](3)
      exec(ds.getimport(Bar, alias='raw'), {}, local)
      exec(ds.getimport(ts.Bar, alias='mod'), {}, local)
      assert ds.getname(local['raw']) == ds.getname(local['mod'])
    likely benign LLM, confidence 0.90 Test execs getimport output for Bar and checks names match.
    Reasoning

    The exec consumes getimport output for the Bar class within a test that compares names and behaviour. The input is generated locally, so there is no injection path.

  48. info warn → info by review dynamic-execution dill/tests/test_sources.py:159:3

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

      exec(ds.getimport(Bar, alias='raw'), {}, local)
      exec(ds.getimport(ts.Bar, alias='mod'), {}, local)
      assert ds.getname(local['raw']) == ds.getname(local['mod'])
      exec(ds.getimport(tm.quad, alias='mod'), {}, local)
    likely benign LLM, confidence 0.90 Test execs getimport strings for Bar and tm.quad and asserts results.
    Reasoning

    Test-only exec of dill-generated import strings, including for tm.quad, followed by assertions. Consistent with normal library testing.

  49. info warn → info by review dynamic-execution dill/tests/test_sources.py:161:3

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

      assert ds.getname(local['raw']) == ds.getname(local['mod'])
      exec(ds.getimport(tm.quad, alias='mod'), {}, local)
      assert local['mod']()(sum)([1,2,3]) == tm.quad()(sum)([1,2,3])
      #FIXME: wrong results for nested functions (e.g. tm.double_add, tm.quadratic)
    likely benign LLM, confidence 0.90 Test execs getimport output for tm.quad and compares results, with a known-issue FIXME.
    Reasoning

    The exec call reconstructs tm.quad via dill's getimport in a test and compares results. The FIXME comment shows this is ordinary development code.

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/uqfoundation/dill dill && cd dill
git checkout 0.4.1
disclude scan --severity info --diff 0.4.0 .