PyPI / pip / 26.2.2

pip 26.2.2

Source
https://github.com/pypa/pip
Tag scanned
26.2.2
Compared with
26.2.1 (0 signals introduced since)
Files
789 scanned, 229 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 149 info
Scan time
23.9 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 36 of 36 warn and critical signals; 36 demoted to info.
Disclude version
4.0.0
Scanned (UTC)
2026-10-21 04:26

Signals

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

  1. info warn → info by review unicode-zero-width AUTHORS.txt:798:2

    U+200B ZERO WIDTH SPACE in source (raw pass, confidence 0.75)

    Sylvain
    S⟨U+200B⟩age Abdullah
    Takayuki SHIMIZUKAWA
    Taneli Hukkinen
    likely benign LLM, confidence 0.97 Zero-width space embedded in an author name in AUTHORS.txt.
    Reasoning

    A zero-width space inside a person's name in an authors list is a stray typographic artifact in a plain text document, not executable code; no security impact.

  2. info critical → info by review dynamic-execution docs/html/user_guide.rst:924:5

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

        eval "`pip completion --bash`"
    likely benign LLM, confidence 0.90 Documentation example evaluating pip's bash completion output.
    Reasoning

    The eval is inside a reStructuredText doc example showing shell completion setup (eval of pip completion output), a standard documented pattern; it is prose, not executed code.

  3. compression ratio 0.764 is >2σ above file mean 0.626 (raw pass, confidence 0.50)

    > "I would like some security advisor, [like in npm]https://docs.npmjs.com/auditing-package-dependencies-for-security-vulnerabilities - it works very well, when you install a package "there are security vulns. with this package - 1 low, 5 medium, 8 high. I haven't come across security issues with Python packages." **
  4. info warn → info by review dynamic-execution src/pip/_internal/commands/configuration.py:248:13

    `subprocess.check_call` called with `shell=True` and a literal command (ast pass, confidence 0.70)

            try:
                subprocess.check_call(f'{editor} "{fname}"', shell=True)
            except FileNotFoundError as e:
                if not e.filename:
    likely benign LLM, confidence 0.85 Launches the user's editor via shell command for pip config edit.
    Reasoning

    Runs the user's configured editor with shell=True, filename interpolated; this is a known pattern for launching editors and the input is user-controlled local config, so not malicious, though the shell quoting is weak.

  5. info critical → info by review dynamic-import src/pip/_internal/commands/install.py:114:13

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

            try:
                __import__(module)
            except ImportError:
                # Record the module as missing so the hook can raise ImportError
    likely benign LLM, confidence 0.93 Dynamic import attempt to detect a missing module for a hook.
    Reasoning

    Standard import-probing of an optional module name inside a try/except ImportError, used to record missing modules; legitimate.

  6. U+200B ZERO WIDTH SPACE in source (in string/comment) (raw pass, confidence 0.45)

        """Fallback for Python without tarfile.data_filter"""
        # NOTE: This function can be removed once pip requires CPython ≥ 3.12.⟨U+200B⟩
        # PEP 706 added tarfile.data_filter, made tarfile extraction operations more secure.
        # This feature is fully supported from CPython 3.12 onward.
  7. info critical → info by review dynamic-import src/pip/_vendor/__init__.py:33:9

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

        try:
            __import__(modulename, globals(), locals(), level=0)
        except ImportError:
            # We can just silently allow import failures to pass here. If we
    likely benign LLM, confidence 0.95 Vendor import redirector importing modules by name.
    Reasoning

    Vendoring shim that imports vendored modules by name and silently tolerates ImportError; this is the well-known pip vendor redirection mechanism.

  8. info critical → info by review dynamic-import src/pip/_vendor/distlib/resources.py:337:13

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

            if package not in sys.modules:
                __import__(package)
            module = sys.modules[package]
            path = getattr(module, '__path__', None)
    likely benign LLM, confidence 0.95 Imports a package dynamically to resolve its resource path.
    Reasoning

    Imports a package by name to locate its __path__ for resource lookup, a normal distlib pattern.

  9. info critical → info by review dynamic-import src/pip/_vendor/distlib/util.py:680:15

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

        else:
            mod = __import__(module_name)
        if dotted_path is None:
            result = mod
    likely benign LLM, confidence 0.95 Resolves a module name from a dotted path for entry points.
    Reasoning

    Standard resolver for dotted paths like 'module:attr' in distlib; the name comes from package metadata, normal behavior for entry point resolution.

  10. info unicode-mixed-script src/pip/_vendor/idna/uts46data.py:8850:6

    identifier `ʼn` mixes scripts: Other + Latin (in string/comment) (raw pass, confidence 0.40)

        None,
        "ʼn",
        "ŋ",
        None,
  11. identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        None,
        "α",
        "β",
        "γ",
  12. identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

        "ζ",
        "η",
        "θ",
        "ι",
  13. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "ι",
        "κ",
        "λ",
        "μ",
  14. identifier `ν` contains homoglyph candidates: ν (03BD)→v (in string/comment) (raw pass, confidence 0.35)

        "μ",
        "ν",
        "ξ",
        "ο",
  15. identifier `ο` contains homoglyph candidates: ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "ξ",
        "ο",
        "π",
        "ρ",
  16. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "π",
        "ρ",
        None,
        "σ",
  17. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        None,
        "κ",
        "ρ",
        "σ",
  18. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "κ",
        "ρ",
        "σ",
        None,
  19. identifier `і` contains homoglyph candidates: і (0456)→i (in string/comment) (raw pass, confidence 0.35)

        "ѕ",
        "і",
        "ї",
        "ј",
  20. identifier `а` contains homoglyph candidates: а (0430)→a (in string/comment) (raw pass, confidence 0.35)

        "џ",
        "а",
        "б",
        "в",
  21. identifier `е` contains homoglyph candidates: е (0435)→e (in string/comment) (raw pass, confidence 0.35)

        "д",
        "е",
        "ж",
        "з",
  22. identifier `о` contains homoglyph candidates: о (043E)→o (in string/comment) (raw pass, confidence 0.35)

        "н",
        "о",
        "п",
        "р",
  23. identifier `р` contains homoglyph candidates: р (0440)→p (in string/comment) (raw pass, confidence 0.35)

        "п",
        "р",
        "с",
        "т",
  24. identifier `с` contains homoglyph candidates: с (0441)→c (in string/comment) (raw pass, confidence 0.35)

        "р",
        "с",
        "т",
        "у",
  25. identifier `у` contains homoglyph candidates: у (0443)→y (in string/comment) (raw pass, confidence 0.35)

        "т",
        "у",
        "ф",
        "х",
  26. identifier `х` contains homoglyph candidates: х (0445)→x (in string/comment) (raw pass, confidence 0.35)

        "ф",
        "х",
        "ц",
        "ч",
  27. identifier `о` contains homoglyph candidates: о (043E)→o (in string/comment) (raw pass, confidence 0.35)

        "д",
        "о",
        "с",
        "т",
  28. identifier `с` contains homoglyph candidates: с (0441)→c (in string/comment) (raw pass, confidence 0.35)

        "о",
        "с",
        "т",
        "ъ",
  29. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "γ",
        "ρ",
        "φ",
        "χ",
  30. info unicode-mixed-script src/pip/_vendor/idna/uts46data.py:10374:6

    identifier `aʾ` mixes scripts: Latin + Other (in string/comment) (raw pass, confidence 0.40)

        None,
        "aʾ",
        "ṡ",
        None,
  31. info unicode-mixed-script src/pip/_vendor/idna/uts46data.py:12023:6

    identifier `kω` mixes scripts: Latin + Greek (in string/comment) (raw pass, confidence 0.40)

        "mw",
        "kω",
        "mω",
        None,
  32. info unicode-mixed-script src/pip/_vendor/idna/uts46data.py:12024:6

    identifier `mω` mixes scripts: Latin + Greek (in string/comment) (raw pass, confidence 0.40)

        "kω",
        "mω",
        None,
        "bq",
  33. identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        None,
        "α",
        "β",
        "γ",
  34. identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

        "ζ",
        "η",
        "θ",
        "ι",
  35. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "ι",
        "κ",
        "λ",
        "μ",
  36. identifier `ν` contains homoglyph candidates: ν (03BD)→v (in string/comment) (raw pass, confidence 0.35)

        "μ",
        "ν",
        "ξ",
        "ο",
  37. identifier `ο` contains homoglyph candidates: ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "ξ",
        "ο",
        "π",
        "ρ",
  38. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "π",
        "ρ",
        "θ",
        "σ",
  39. identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        "∇",
        "α",
        "β",
        "γ",
  40. identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

        "ζ",
        "η",
        "θ",
        "ι",
  41. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "ι",
        "κ",
        "λ",
        "μ",
  42. identifier `ν` contains homoglyph candidates: ν (03BD)→v (in string/comment) (raw pass, confidence 0.35)

        "μ",
        "ν",
        "ξ",
        "ο",
  43. identifier `ο` contains homoglyph candidates: ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "ξ",
        "ο",
        "π",
        "ρ",
  44. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "π",
        "ρ",
        "σ",
        "τ",
  45. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "θ",
        "κ",
        "φ",
        "ρ",
  46. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "φ",
        "ρ",
        "π",
        "α",
  47. identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        "π",
        "α",
        "β",
        "γ",
  48. identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

        "ζ",
        "η",
        "θ",
        "ι",
  49. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "ι",
        "κ",
        "λ",
        "μ",
  50. identifier `ν` contains homoglyph candidates: ν (03BD)→v (in string/comment) (raw pass, confidence 0.35)

        "μ",
        "ν",
        "ξ",
        "ο",
  51. identifier `ο` contains homoglyph candidates: ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "ξ",
        "ο",
        "π",
        "ρ",
  52. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "π",
        "ρ",
        "θ",
        "σ",
  53. identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        "∇",
        "α",
        "β",
        "γ",
  54. identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

        "ζ",
        "η",
        "θ",
        "ι",
  55. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "ι",
        "κ",
        "λ",
        "μ",
  56. identifier `ν` contains homoglyph candidates: ν (03BD)→v (in string/comment) (raw pass, confidence 0.35)

        "μ",
        "ν",
        "ξ",
        "ο",
  57. identifier `ο` contains homoglyph candidates: ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "ξ",
        "ο",
        "π",
        "ρ",
  58. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "π",
        "ρ",
        "σ",
        "τ",
  59. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "θ",
        "κ",
        "φ",
        "ρ",
  60. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "φ",
        "ρ",
        "π",
        "α",
  61. identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        "π",
        "α",
        "β",
        "γ",
  62. identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

        "ζ",
        "η",
        "θ",
        "ι",
  63. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "ι",
        "κ",
        "λ",
        "μ",
  64. identifier `ν` contains homoglyph candidates: ν (03BD)→v (in string/comment) (raw pass, confidence 0.35)

        "μ",
        "ν",
        "ξ",
        "ο",
  65. identifier `ο` contains homoglyph candidates: ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "ξ",
        "ο",
        "π",
        "ρ",
  66. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "π",
        "ρ",
        "θ",
        "σ",
  67. identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        "∇",
        "α",
        "β",
        "γ",
  68. identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

        "ζ",
        "η",
        "θ",
        "ι",
  69. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "ι",
        "κ",
        "λ",
        "μ",
  70. identifier `ν` contains homoglyph candidates: ν (03BD)→v (in string/comment) (raw pass, confidence 0.35)

        "μ",
        "ν",
        "ξ",
        "ο",
  71. identifier `ο` contains homoglyph candidates: ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "ξ",
        "ο",
        "π",
        "ρ",
  72. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "π",
        "ρ",
        "σ",
        "τ",
  73. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "θ",
        "κ",
        "φ",
        "ρ",
  74. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "φ",
        "ρ",
        "π",
        "α",
  75. identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        "π",
        "α",
        "β",
        "γ",
  76. identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

        "ζ",
        "η",
        "θ",
        "ι",
  77. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "ι",
        "κ",
        "λ",
        "μ",
  78. identifier `ν` contains homoglyph candidates: ν (03BD)→v (in string/comment) (raw pass, confidence 0.35)

        "μ",
        "ν",
        "ξ",
        "ο",
  79. identifier `ο` contains homoglyph candidates: ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "ξ",
        "ο",
        "π",
        "ρ",
  80. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "π",
        "ρ",
        "θ",
        "σ",
  81. identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        "∇",
        "α",
        "β",
        "γ",
  82. identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

        "ζ",
        "η",
        "θ",
        "ι",
  83. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "ι",
        "κ",
        "λ",
        "μ",
  84. identifier `ν` contains homoglyph candidates: ν (03BD)→v (in string/comment) (raw pass, confidence 0.35)

        "μ",
        "ν",
        "ξ",
        "ο",
  85. identifier `ο` contains homoglyph candidates: ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "ξ",
        "ο",
        "π",
        "ρ",
  86. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "π",
        "ρ",
        "σ",
        "τ",
  87. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "θ",
        "κ",
        "φ",
        "ρ",
  88. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "φ",
        "ρ",
        "π",
        "α",
  89. identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        "π",
        "α",
        "β",
        "γ",
  90. identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

        "ζ",
        "η",
        "θ",
        "ι",
  91. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "ι",
        "κ",
        "λ",
        "μ",
  92. identifier `ν` contains homoglyph candidates: ν (03BD)→v (in string/comment) (raw pass, confidence 0.35)

        "μ",
        "ν",
        "ξ",
        "ο",
  93. identifier `ο` contains homoglyph candidates: ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "ξ",
        "ο",
        "π",
        "ρ",
  94. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "π",
        "ρ",
        "θ",
        "σ",
  95. identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        "∇",
        "α",
        "β",
        "γ",
  96. identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

        "ζ",
        "η",
        "θ",
        "ι",
  97. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "ι",
        "κ",
        "λ",
        "μ",
  98. identifier `ν` contains homoglyph candidates: ν (03BD)→v (in string/comment) (raw pass, confidence 0.35)

        "μ",
        "ν",
        "ξ",
        "ο",
  99. identifier `ο` contains homoglyph candidates: ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "ξ",
        "ο",
        "π",
        "ρ",
  100. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "π",
        "ρ",
        "σ",
        "τ",
  101. identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "θ",
        "κ",
        "φ",
        "ρ",
  102. identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "φ",
        "ρ",
        "π",
        "ϝ",
  103. identifier `а` contains homoglyph candidates: а (0430)→a (in string/comment) (raw pass, confidence 0.35)

        None,
        "а",
        "б",
        "в",
  104. identifier `е` contains homoglyph candidates: е (0435)→e (in string/comment) (raw pass, confidence 0.35)

        "д",
        "е",
        "ж",
        "з",
  105. identifier `о` contains homoglyph candidates: о (043E)→o (in string/comment) (raw pass, confidence 0.35)

        "м",
        "о",
        "п",
        "р",
  106. identifier `р` contains homoglyph candidates: р (0440)→p (in string/comment) (raw pass, confidence 0.35)

        "п",
        "р",
        "с",
        "т",
  107. identifier `с` contains homoglyph candidates: с (0441)→c (in string/comment) (raw pass, confidence 0.35)

        "р",
        "с",
        "т",
        "у",
  108. identifier `у` contains homoglyph candidates: у (0443)→y (in string/comment) (raw pass, confidence 0.35)

        "т",
        "у",
        "ф",
        "х",
  109. identifier `х` contains homoglyph candidates: х (0445)→x (in string/comment) (raw pass, confidence 0.35)

        "ф",
        "х",
        "ц",
        "ч",
  110. identifier `і` contains homoglyph candidates: і (0456)→i (in string/comment) (raw pass, confidence 0.35)

        "ә",
        "і",
        "ј",
        "ө",
  111. identifier `а` contains homoglyph candidates: а (0430)→a (in string/comment) (raw pass, confidence 0.35)

        "ӏ",
        "а",
        "б",
        "в",
  112. identifier `е` contains homoglyph candidates: е (0435)→e (in string/comment) (raw pass, confidence 0.35)

        "д",
        "е",
        "ж",
        "з",
  113. identifier `о` contains homoglyph candidates: о (043E)→o (in string/comment) (raw pass, confidence 0.35)

        "л",
        "о",
        "п",
        "с",
  114. identifier `с` contains homoglyph candidates: с (0441)→c (in string/comment) (raw pass, confidence 0.35)

        "п",
        "с",
        "у",
        "ф",
  115. identifier `у` contains homoglyph candidates: у (0443)→y (in string/comment) (raw pass, confidence 0.35)

        "с",
        "у",
        "ф",
        "х",
  116. identifier `х` contains homoglyph candidates: х (0445)→x (in string/comment) (raw pass, confidence 0.35)

        "ф",
        "х",
        "ц",
        "ч",
  117. identifier `і` contains homoglyph candidates: і (0456)→i (in string/comment) (raw pass, confidence 0.35)

        "ґ",
        "і",
        "ѕ",
        "џ",
  118. info warn → info by review dynamic-execution src/pip/_vendor/packaging/licenses/__init__.py:144:9

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

        try:
            compile(python_expression, "", "eval")
        except SyntaxError:
            message = f"Invalid license expression: {raw_license_expression!r}"
    likely benign LLM, confidence 0.85 Syntax-checks a license expression via compile without running it.
    Reasoning

    compile with mode 'eval' is used only to syntax-check a license expression and catch SyntaxError; it is not executed, so it is a validation pattern.

  119. info critical → info by review dynamic-import src/pip/_vendor/pkg_resources/__init__.py:427:9

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

        except KeyError:
            __import__(moduleOrReq)
            module = sys.modules[moduleOrReq]
        loader = getattr(module, '__loader__', None)
    likely benign LLM, confidence 0.93 Imports a module by name to obtain its loader in pkg_resources.
    Reasoning

    Imports a requested module name in pkg_resources to find its loader, a documented behavior of the library.

  120. info critical → info by review frame-introspection src/pip/_vendor/pkg_resources/__init__.py:743:14

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

            """Locate distribution for `requires` and run `script_name` script"""
            ns = sys._getframe(1).f_globals
            name = ns['__name__']
            ns.clear()
    likely benign LLM, confidence 0.85 Accesses caller frame globals to run a distribution script.
    Reasoning

    Used in run_script to access the caller's globals for executing a distribution script, a legitimate setuptools pattern; the frame-introspection plus exit/exec co-occurrence is a heuristic match in a large legitimate module.

  121. info warn → info by review dynamic-execution src/pip/_vendor/pkg_resources/__init__.py:1713:20

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

                source = _read_utf8_with_fallback(script_filename)
                code = compile(source, script_filename, 'exec')
                exec(code, namespace, namespace)
            else:
    likely benign LLM, confidence 0.85 Compiles installed script source for execution in run_script.
    Reasoning

    Compiles a script file's source for run_script, executing installed console script code, which is the expected function of this API; source comes from installed distributions.

  122. info warn → info by review dynamic-execution src/pip/_vendor/pkg_resources/__init__.py:1714:13

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

                code = compile(source, script_filename, 'exec')
                exec(code, namespace, namespace)
            else:
                from linecache import cache
    likely benign LLM, confidence 0.85 Executes installed distribution script code via exec.
    Reasoning

    Executes the compiled script of an installed distribution as part of pkg_resources run_script; legitimate by design, not obfuscated.

  123. info warn → info by review dynamic-execution src/pip/_vendor/pkg_resources/__init__.py:1724:27

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

                )
                script_code = compile(script_text, script_filename, 'exec')
                exec(script_code, namespace, namespace)
    likely benign LLM, confidence 0.85 Compiles script text from distribution metadata for execution.
    Reasoning

    Same run_script pattern compiling script text from a distribution's metadata for execution; expected behavior of the library.

  124. info warn → info by review dynamic-execution src/pip/_vendor/pkg_resources/__init__.py:1725:13

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

                script_code = compile(script_text, script_filename, 'exec')
                exec(script_code, namespace, namespace)
    
        def _has(self, path) -> bool:
    likely benign LLM, confidence 0.85 Executes distribution script text via exec in run_script.
    Reasoning

    Executes the compiled script text in run_script; legitimate functionality of pkg_resources, consistent with the surrounding code.

  125. info critical → info by review dynamic-import src/pip/_vendor/pkg_resources/__init__.py:2530:17

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

                if parent not in _namespace_packages:
                    __import__(parent)
                try:
                    path = sys.modules[parent].__path__
    likely benign LLM, confidence 0.93 Imports a parent namespace package to read its __path__.
    Reasoning

    Imports the parent namespace package before reading its __path__, a standard namespace-package handling step in pkg_resources.

  126. info critical → info by review dynamic-import src/pip/_vendor/pkg_resources/__init__.py:2751:18

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

            """
            module = __import__(self.module_name, fromlist=['__name__'], level=0)
            try:
                return functools.reduce(getattr, self.attrs, module)
    likely benign LLM, confidence 0.90 Dynamic __import__ of an entry point module name for plugin resolution.
    Reasoning

    EntryPoint.resolve imports a module by its configured name, a standard plugin-loading mechanism in setuptools/pkg_resources vendored in pip. Dynamic import of a configured module name is expected.

  127. info critical → info by review frame-introspection src/pip/_vendor/pkg_resources/__init__.py:3411:15

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

            # the pkg_resources module, to use for the warning
            while sys._getframe(level).f_globals is g:
                level += 1
        except ValueError:
    likely benign LLM, confidence 0.90 Frame walk to compute warning stacklevel in pkg_resources.
    Reasoning

    sys._getframe is used in a warnings helper to compute stacklevel by walking frames until leaving the module. This is a standard idiom for warning attribution, not anti-analysis behavior.

  128. info critical → info by review dynamic-import src/pip/_vendor/pygments/formatters/__init__.py:38:11

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

        """Load a formatter (and all others in the module too)."""
        mod = __import__(module_name, None, None, ['__all__'])
        for formatter_name in mod.__all__:
            cls = getattr(mod, formatter_name)
    likely benign LLM, confidence 0.92 Pygments dynamic import of a formatter module by name.
    Reasoning

    Pygments loads its own built-in formatter modules by name via __import__, a normal plugin loader pattern in a well-known vendored library.

  129. info warn → info by review dynamic-execution src/pip/_vendor/pygments/formatters/__init__.py:103:13

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

            with open(filename, 'rb') as f:
                exec(f.read(), custom_namespace)
            # Retrieve the class `formattername` from that namespace
            if formattername not in custom_namespace:
    likely benign LLM, confidence 0.85 Executes a user-specified custom formatter Python file.
    Reasoning

    Pygments exec's a user-supplied custom formatter file passed explicitly by the caller via the API. This is a documented feature, not hidden execution, though exec of file contents is powerful and warrants awareness.

  130. info critical → info by review dynamic-import src/pip/_vendor/pygments/lexers/__init__.py:45:11

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

        """Load a lexer (and all others in the module too)."""
        mod = __import__(module_name, None, None, ['__all__'])
        for lexer_name in mod.__all__:
            cls = getattr(mod, lexer_name)
    likely benign LLM, confidence 0.92 Pygments dynamic import of a lexer module by name.
    Reasoning

    Standard Pygments lexer plugin loading by module name in its own package.

  131. info warn → info by review dynamic-execution src/pip/_vendor/pygments/lexers/__init__.py:154:13

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

            with open(filename, 'rb') as f:
                exec(f.read(), custom_namespace)
            # Retrieve the class `lexername` from that namespace
            if lexername not in custom_namespace:
    likely benign LLM, confidence 0.85 Executes a user-specified custom lexer Python file.
    Reasoning

    Pygments executes a user-supplied custom lexer file explicitly provided by the caller, a documented feature.

  132. info critical → info by review dynamic-import src/pip/_vendor/pygments/sphinxext.py:161:19

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

                module = data[0]
                mod = __import__(module, None, None, [classname])
                self.filenames.add(mod.__file__)
                cls = getattr(mod, classname)
    likely benign LLM, confidence 0.90 Dynamic import of a lexer class module named in Sphinx docs.
    Reasoning

    Sphinx extension imports lexer classes named in documentation directives; expected behavior for a documentation tool.

  133. info critical → info by review dynamic-import src/pip/_vendor/pygments/sphinxext.py:221:19

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

                module = data[0]
                mod = __import__(module, None, None, [classname])
                self.filenames.add(mod.__file__)
                cls = getattr(mod, classname)
    likely benign LLM, confidence 0.90 Dynamic import of a lexer class module for Sphinx docs.
    Reasoning

    Same pattern as the other sphinxext import: resolving a documented lexer class by module name.

  134. info critical → info by review dynamic-import src/pip/_vendor/pygments/styles/__init__.py:45:15

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

        try:
            mod = __import__(mod, None, None, [cls])
        except ImportError:
            raise ClassNotFound(f"Could not find style module {mod!r}" +
    likely benign LLM, confidence 0.90 Pygments dynamic import of a style module by name.
    Reasoning

    Pygments loads a style module by name from its own package with a ClassNotFound fallback; standard plugin loading.

  135. compression ratio 0.629 is >2σ above file mean 0.384 (raw pass, confidence 0.50)

    
    Sc = '$\xa2-\xa5\u058f\u060b\u07fe-\u07ff\u09f2-\u09f3\u09fb\u0af1\u0bf9\u0e3f\u17db\u20a0-\u20bf\ua838\ufdfc\ufe69\uff04\uffe0-\uffe1\uffe5-\uffe6\U0001ecb0'
  136. info warn → info by review dynamic-attribute src/pip/_vendor/pygments/unistring.py:83:20

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

    def combine(*args):
        return ''.join(globals()[cat] for cat in args)
    likely benign LLM, confidence 0.90 Combines Unicode category constants by name via globals().
    Reasoning

    globals() lookup of Unicode category string constants generated in the same module; a plain data-table combiner with no payload behavior.

  137. info warn → info by review dynamic-attribute src/pip/_vendor/pygments/unistring.py:90:20

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

            newcats.remove(arg)
        return ''.join(globals()[cat] for cat in newcats)
    likely benign LLM, confidence 0.90 Builds Unicode category ranges by name from module globals.
    Reasoning

    Same as the other unistring combiner: looks up Unicode range constants in module globals for regex character classes.

  138. info warn → info by review dynamic-execution src/pip/_vendor/pygments/unistring.py:115:10

    `open(__file__)` — file reads its own source, common pattern for extracting payloads hidden in comments (ast pass, confidence 0.85)

    
        with open(__file__, encoding='utf-8') as fp:
            content = fp.read()
    likely benign LLM, confidence 0.90 Reads its own file while regenerating Unicode tables.
    Reasoning

    This is a generator script section that reads its own source to rewrite the generated unistring data table when run as __main__; it is not extracting hidden payloads at import time.

  139. info warn → info by review dynamic-execution src/pip/_vendor/pygments/unistring.py:139:10

    `open(__file__)` — file reads its own source, common pattern for extracting payloads hidden in comments (ast pass, confidence 0.85)

    
        with open(__file__, 'w', encoding='utf-8') as fp:
            fp.write(header)
    likely benign LLM, confidence 0.90 Rewrites its own source file with regenerated Unicode data.
    Reasoning

    Writes a regenerated header into its own source file as part of a maintenance script for Unicode tables; not a payload dropper.

  140. info warn → info by review dynamic-attribute src/pip/_vendor/pyproject_hooks/_in_process/_in_process.py:367:12

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

    
        hook = globals()[hook_name]
    
        hook_input = read_json(pjoin(control_dir, "input.json"))
    likely benign LLM, confidence 0.90 Dispatches a PEP 517 build hook by name from globals.
    Reasoning

    Looks up a build hook function by name from globals in the pyproject_hooks in-process runner; the name comes from the build backend's defined hook set, a standard dispatch pattern.

  141. info warn → info by review dynamic-attribute src/pip/_vendor/requests/packages.py:10:5

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

        vendored_package = "pip._vendor." + package
        locals()[package] = __import__(vendored_package)
        # This traversal is apparently necessary such that the identities are
        # preserved (requests.packages.urllib3.* is urllib3.*)
    likely benign LLM, confidence 0.90 Aliases vendored packages into locals for backward-compatible imports.
    Reasoning

    Legacy shim that aliases vendored urllib3/chardet/idna modules into the requests.packages namespace so old imports keep working; a known, benign compatibility mechanism.

  142. info critical → info by review dynamic-import src/pip/_vendor/requests/packages.py:10:25

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

        vendored_package = "pip._vendor." + package
        locals()[package] = __import__(vendored_package)
        # This traversal is apparently necessary such that the identities are
        # preserved (requests.packages.urllib3.* is urllib3.*)
    likely benign LLM, confidence 0.93 Vendored requests compatibility shim that dynamically imports pip-vendored submodules.
    Reasoning

    This is the standard vendored-requests shim that aliases vendored urllib3/chardet/idna modules under the requests.packages namespace. The dynamic __import__ is over a fixed prefix plus a package name from a hardcoded list, so it is legitimate vendoring code, not an attack.

  143. info warn → info by review frame-introspection src/pip/_vendor/rich/console.py:1929:26

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

                # Fallback to the slower stack
                frame_info = inspect.stack()[offset]
                return frame_info.filename, frame_info.lineno, frame_info.frame.f_locals
    likely benign LLM, confidence 0.90 Fallback call-stack introspection in rich console to find caller filename and line.
    Reasoning

    Rich uses inspect.stack() as a fallback to locate the caller's frame for logging/printing metadata. This is ordinary library behavior with no exfiltration or hidden execution in the snippet.

  144. info critical → info by review builtins-write src/pip/_vendor/rich/pretty.py:204:13

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

                assert console is not None
                builtins._ = None  # type: ignore[attr-defined]
                console.print(
                    (
    likely benign LLM, confidence 0.90 Temporarily sets builtins._ to emulate the REPL last-value convention during pretty printing.
    Reasoning

    Rich's pretty printer temporarily sets builtins._ to None and then to the value, mirroring the interactive REPL's last-result convention for pretty-printing. It is a known, intentional pattern in rich, though it does mutate a global builtin; it is not malicious.

  145. info critical → info by review builtins-write src/pip/_vendor/rich/pretty.py:221:13

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

                )
                builtins._ = value  # type: ignore[attr-defined]
    
        try:
    likely benign LLM, confidence 0.90 Sets builtins._ to the pretty-printed value to mirror REPL last-result behavior.
    Reasoning

    Same pattern as the companion finding: rich's pretty.py sets builtins._ to the printed value so that the REPL's '_' convention works. Legitimate library behavior, though a global side effect worth noting.

  146. info warn → info by review decoder-decompress-payload src/pip/_vendor/urllib3/response.py:65:21

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

            self._unfed_data = b""
            self._obj = zlib.decompressobj()
    
        def decompress(self, data: bytes, max_length: int = -1) -> bytes:
    likely benign LLM, confidence 0.85 Streaming HTTP content decoder in urllib3 using zlib decompressobj for response bodies.
    Reasoning

    urllib3 uses zlib.decompressobj to decode HTTP gzip/deflate content-encoding responses. The 'embedded payload' framing is a false positive from the decompress call; this is standard HTTP response decoding.

  147. identifier `ˈpjœr` mixes scripts: Other + Latin (in string/comment) (raw pass, confidence 0.40)

            sys.stdout.buffer.write(
                "* Björk Guðmundsdóttir [ˈpjœr̥k ˈkvʏðmʏntsˌtoʊhtɪr]".encode()
            )
        else:
  148. identifier `ˈkvʏðmʏntsˌtoʊhtɪr` mixes scripts: Other + Latin (in string/comment) (raw pass, confidence 0.40)

            sys.stdout.buffer.write(
                "* Björk Guðmundsdóttir [ˈpjœr̥k ˈkvʏðmʏntsˌtoʊhtɪr]".encode()
            )
        else:
  149. info critical → info by review dynamic-execution tests/functional/test_no_color.py:35:16

    `subprocess.Popen` with `shell=True` and a non-literal command — runtime-determined shell invocation (ast pass, confidence 0.85)

            cmd = command.format(option)
            proc = subprocess.Popen(
                cmd,
                shell=True,
    likely benign LLM, confidence 0.80 Functional test helper invoking a formatted command via subprocess with shell=True.
    Reasoning

    This is a test helper running a pip command string formatted with an option, with shell=True. The command is built from test-controlled literals, so there is no untrusted input. It is a test-harness pattern, though shell=True with formatting is poor hygiene.

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/pypa/pip pip && cd pip
git checkout 26.2.2
disclude scan --severity info --diff 26.2.1 .