PyPI / scikit-learn / 1.9.1

scikit-learn 1.9.1

Source
https://github.com/scikit-learn/scikit-learn
Tag scanned
1.9.1
Compared with
1.9.0 (8 signals introduced since)
Files
1297 scanned, 380 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 20 info
Scan time
15.0 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 19 of 19 warn and critical signals; 19 demoted to info.
Disclude version
4.0.0
Scanned (UTC)
2026-10-14 18:39

Signals

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

  1. info critical → info by review dynamic-import sklearn/externals/array_api_compat/cupy/__init__.py:12:1 new in this release

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

    # See the comment in the numpy __init__.py
    __import__(__spec__.parent + '.linalg')
    __import__(__spec__.parent + '.fft')
    likely benign LLM, confidence 0.90 Imports the package's own linalg and fft submodules via __spec__.parent in vendored array-api code.
    Reasoning

    Vendored array_api_compat uses __import__ on the package's own __spec__.parent plus fixed submodule suffixes to load linalg and fft; deterministic, self-referential, and documented in the vendored library.

  2. info critical → info by review dynamic-import sklearn/externals/array_api_compat/cupy/__init__.py:13:1 new in this release

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

    __import__(__spec__.parent + '.linalg')
    __import__(__spec__.parent + '.fft')
    
    __array_api_version__: Final = '2025.12'
    likely benign LLM, confidence 0.90 Imports the package's own fft submodule via __spec__.parent in vendored array-api code.
    Reasoning

    Same vendored pattern importing own submodules relative to __spec__.parent; no external input.

  3. info critical → info by review dynamic-import sklearn/externals/array_api_compat/dask/array/__init__.py:16:1 new in this release

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

    # See the comment in the numpy __init__.py
    __import__(__spec__.parent + '.linalg')
    __import__(__spec__.parent + '.fft')
    likely benign LLM, confidence 0.90 Imports own linalg submodule via __spec__.parent in vendored dask array compat code.
    Reasoning

    Vendored array_api_compat self-import of linalg and fft using __spec__.parent; benign library idiom.

  4. info critical → info by review dynamic-import sklearn/externals/array_api_compat/dask/array/__init__.py:17:1 new in this release

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

    __import__(__spec__.parent + '.linalg')
    __import__(__spec__.parent + '.fft')
    
    __all__ = sorted(
    likely benign LLM, confidence 0.90 Imports own fft submodule via __spec__.parent in vendored dask array compat code.
    Reasoning

    Same vendored self-import idiom; no external or attacker-controlled input.

  5. info critical → info by review dynamic-import sklearn/externals/array_api_compat/numpy/__init__.py:22:1 new in this release

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

    # dynamically so that the library can be vendored.
    __import__(__spec__.parent + ".linalg")
    
    __import__(__spec__.parent + ".fft")
    likely benign LLM, confidence 0.90 Imports own linalg submodule via __spec__.parent in vendored numpy compat code.
    Reasoning

    Vendored array_api_compat idiom importing own linalg submodule relative to __spec__.parent so the library can be vendored; benign.

  6. info critical → info by review dynamic-import sklearn/externals/array_api_compat/numpy/__init__.py:24:1 new in this release

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

    
    __import__(__spec__.parent + ".fft")
    
    from .linalg import matrix_transpose, vecdot  # type: ignore[no-redef]  # noqa: F401
    likely benign LLM, confidence 0.95 Imports the sibling fft submodule of the package via __spec__.parent-relative __import__.
    Reasoning

    The __import__ call builds a module name from __spec__.parent plus a literal '.fft' suffix, which is the standard relative-submodule loading idiom in vendored array_api_compat code. The argument is not attacker-controlled input, and the same pattern appears in sibling modules. This is legitimate lazy submodule loading.

  7. info critical → info by review dynamic-import sklearn/externals/array_api_compat/torch/__init__.py:13:1 new in this release

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

    # See the comment in the numpy __init__.py
    __import__(__spec__.parent + '.linalg')
    __import__(__spec__.parent + '.fft')
    likely benign LLM, confidence 0.95 Loads the package's linalg submodule relative to its own package spec.
    Reasoning

    Same vendored array_api_compat idiom: __import__ on __spec__.parent plus a fixed '.linalg' suffix to load a sibling submodule. No external input reaches the expression, so it is benign.

  8. info critical → info by review dynamic-import sklearn/externals/array_api_compat/torch/__init__.py:14:1 new in this release

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

    __import__(__spec__.parent + '.linalg')
    __import__(__spec__.parent + '.fft')
    
    __array_api_version__: Final = '2025.12'
    likely benign LLM, confidence 0.95 Loads the package's fft submodule relative to its own package spec.
    Reasoning

    Identical to the previous finding: a fixed relative submodule name ('.fft') concatenated to __spec__.parent in a vendored compatibility shim. Not an injection or dropper pattern.

  9. info warn → info by review dynamic-import build_tools/circle/build_doc.sh:175:1

    `source` called with a dynamic path — sourcing a variable script path (ast pass, confidence 0.75)

    bash ./miniconda.sh -b -p $MINIFORGE_PATH
    source $MINIFORGE_PATH/etc/profile.d/conda.sh
    conda activate
    likely benign LLM, confidence 0.90 Sources conda profile script from a variable Miniforge install path in a CI build script.
    Reasoning

    Sourcing a conda activation script from a variable install path set by the build itself is standard CI setup; not obfuscation.

  10. info warn → info by review dynamic-import build_tools/github/create_gpu_environment.sh:8:1

    `source` called with a dynamic path — sourcing a variable script path (ast pass, confidence 0.75)

    bash Miniforge3-$(uname)-$(uname -m).sh -b -p "${HOME}/conda"
    source "${HOME}/conda/etc/profile.d/conda.sh"
    likely benign LLM, confidence 0.90 Sources the conda init script from a user-local Miniforge installation.
    Reasoning

    Installs Miniforge into HOME and sources its conda.sh; ordinary environment bootstrap with a fixed layout.

  11. command name is a variable (`$CMD`) that this file sets only to plain text (ast pass, confidence 0.40)

    pushd $TEST_DIR
    $CMD -m sklearn.utils.tests.test_estimator_checks
    popd
  12. info critical → info by review dynamic-execution build_tools/github/test_script.sh:67:1

    `eval` called on a dynamic (variable/substitution) expression (ast pass, confidence 0.90)

    set -x
    eval "$TEST_CMD"
    set +x
    likely benign LLM, confidence 0.75 Evals a TEST_CMD variable to run tests in CI with tracing enabled.
    Reasoning

    eval on a test command variable in a CI test script is a common but risky pattern; the variable is set by the repository's own CI configuration, not attacker-controlled input. Benign in context, though eval of a variable is worth noting.

  13. info warn → info by review dynamic-import build_tools/shared.sh:52:9

    `source` called with a dynamic path — sourcing a variable script path (ast pass, confidence 0.75)

        elif [[ "$DISTRIB" == "ubuntu" || "$DISTRIB" == "debian-32" ]]; then
            source $VIRTUALENV/bin/activate
        fi
    }
    likely benign LLM, confidence 0.85 Sources a virtualenv activate script from a variable VIRTUALENV path.
    Reasoning

    Activates a virtualenv from a variable path in a CI helper function; standard usage.

  14. info critical → info by review dynamic-import doc/sphinxext/github_link.py:43:14

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

        class_name = info["fullname"].split(".")[0]
        module = __import__(info["module"], fromlist=[class_name])
        obj = attrgetter(info["fullname"])(module)
    likely benign LLM, confidence 0.90 Imports a documented module by name to resolve source links for Sphinx docs.
    Reasoning

    Sphinx extension importing the module named in the documented object's info; this is the expected way to resolve documented objects for source linking.

  15. info critical → info by review dynamic-import doc/sphinxext/github_link.py:62:56

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

        try:
            fn = os.path.relpath(fn, start=os.path.dirname(__import__(package).__file__))
        except ValueError:
            return None
    likely benign LLM, confidence 0.90 Imports a package to compute relative file paths for GitHub source links.
    Reasoning

    Imports the package name to locate its file path for linking in docs generation; benign doc tooling.

  16. info warn → info by review dynamic-attribute sklearn/__init__.py:134:20

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

            try:
                return globals()[name]
            except KeyError:
                raise AttributeError(f"Module 'sklearn' has no attribute '{name}'")
    likely benign LLM, confidence 0.90 Module-level __getattr__ that looks up names in globals for lazy attribute access.
    Reasoning

    Module __getattr__ lazily resolving submodule names from globals is a standard lazy-loading pattern; no hidden execution.

  17. info warn → info by review dynamic-attribute sklearn/datasets/__init__.py:166:16

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

        try:
            return globals()[name]
        except KeyError:
            # This is turned into the appropriate ImportError
    likely benign LLM, confidence 0.90 Module __getattr__ resolving names via globals for lazy loading in sklearn.datasets.
    Reasoning

    Same standard module __getattr__ lazy-loading pattern as the top-level package.

  18. info warn → info by review frame-introspection sklearn/tests/metadata_routing_common.py:47:13

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

        ]
        stack = inspect.stack()
        # for callee, extract the innermost `function` (which is in METHODS) from the
        # stack; for caller, extract the *outermost* matching function so the expected
    likely benign LLM, confidence 0.93 Test utility inspects the call stack to locate the calling method for metadata routing assertions.
    Reasoning

    Test helper uses inspect.stack() to find which method invoked a routing check, a common and legitimate testing technique. It reads frames only and performs no unsafe action.

  19. info critical → info by review dynamic-import sklearn/tests/test_common.py:147:19

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

                continue
            package = __import__(modname, fromlist="dummy")
            for name in getattr(package, "__all__", ()):
                assert hasattr(package, name), "Module '{0}' has no attribute '{1}'".format(
    likely benign LLM, confidence 0.90 Test imports sklearn submodules by discovered name to verify their __all__ exports.
    Reasoning

    Test iterates over module names from a package listing and imports each to check __all__ attributes. The modname comes from pkgutil-style discovery of the project's own modules, not untrusted input. Legitimate test code.

  20. info critical → info by review dynamic-import sklearn/utils/tests/test_estimator_checks.py:1729:13

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

            try:
                importlib.__import__(lib)
            except ImportError:
                raise SkipTest(f"Library {lib} is not installed")
    likely benign LLM, confidence 0.90 Test probes for an optional dependency via importlib.__import__ and skips if missing.
    Reasoning

    Test checks whether an optional library is installed by importing it and skipping on ImportError. The lib name comes from a fixed list in the test. Standard optional-dependency guard.

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/scikit-learn/scikit-learn scikit-learn && cd scikit-learn
git checkout 1.9.1
disclude scan --severity info --diff 1.9.0 .