PyPI / ipython / 9.18.0

ipython 9.18.0

Source
https://github.com/ipython/ipython
Artifact scanned
ipython-9.18.0-py3-none-any.whl (wheel · 634.4 KB · SHA-256 d9b8e19267e8…)
Compared with
ipython-9.17.1-py3-none-any.whl (0 signals introduced since)
Files
179 scanned, 15 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 97 info
Scan time
46.2 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 70 of 70 warn and critical signals; 70 demoted to info.
Disclude version
4.3.0
Scanned (UTC)
2026-10-30 14:28

Signals

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

  1. info warn → info by review dynamic-execution IPython/core/async_helpers.py:157:16

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

        try:
            code = compile(
                cell, "<>", "exec", flags=getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
            )
    likely benign LLM, confidence 0.93 Compiles interactive cell source with the top-level await flag.
    Reasoning

    This is IPython's standard helper for compiling cell source with the top-level-await flag. The compile input is user cell code in an interactive shell, which is the tool's purpose, not hidden obfuscation.

  2. info warn → info by review dynamic-execution IPython/core/compilerop.py:90:16

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

            and are passed to the built-in compile function."""
            return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
    
        def reset_compiler_flags(self) -> None:
    likely benign LLM, confidence 0.93 Wrapper around the built-in compile that tracks compiler flags for cell execution.
    Reasoning

    This is the compiler wrapper that IPython uses to compile cells while tracking __future__ flags. Compiling runtime source is expected in a REPL compiler module.

  3. info unicode-homoglyph IPython/core/completer.py:31:5

    identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        \\alpha<tab>
        α
    
    or using unicode completion:
  4. info unicode-homoglyph IPython/core/completer.py:39:5

    identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        \\GREEK SMALL LETTER ALPHA<tab>
        α
  5. info unicode-homoglyph IPython/core/completer.py:57:7

    identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

    
        \\α<tab>
        \\alpha
  6. info unicode-homoglyph IPython/core/completer.py:3317:54

    identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

    
            This does  ``\\GREEK SMALL LETTER ETA`` -> ``η``
    
            Works only on valid python 3 identifier, or on combining characters that
  7. info unicode-homoglyph IPython/core/completer.py:3350:70

    identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

    
            This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``α``
            """
            fragment, matches = self.latex_matches(context.text_until_cursor)
  8. info unicode-homoglyph IPython/core/completer.py:3360:70

    identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

    
            This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``α``
    
            .. deprecated:: 8.6
  9. info unicode-homoglyph IPython/core/completer.py:3372:30

    identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

                    # Try to complete a full latex symbol to unicode
                    # \\alpha -> α
                    return s, [latex_symbols[s]]
                else:
  10. info critical → info by review frame-introspection IPython/core/debugger.py:382:21

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

            if frame is None:
                frame = sys._getframe().f_back
            self.initial_frame = frame
            return super().set_trace(frame, **kwargs)
    likely benign LLM, confidence 0.90 Debugger set_trace retrieves the caller's frame via sys._getframe.
    Reasoning

    sys._getframe().f_back is the standard way for a debugger's set_trace to locate its caller. The co-occurrence with exit/exec/eval in the same file is a generic heuristic hit on a debugger module, not anti-analysis behaviour.

  11. info warn → info by review dynamic-execution IPython/core/debugger.py:953:21

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

                try:
                    x = eval(arg, {}, {})
                    if type(x) == type(()):
                        first, last = x  # type: ignore[misc]
    likely benign LLM, confidence 0.90 Debugger command evaluates user-entered expression text.
    Reasoning

    This is the pdb-style handler that evaluates user-typed expressions at the debugger prompt, using restricted empty globals and locals. That is the intended function of the debugger.

  12. info critical → info by review frame-introspection IPython/core/debugger.py:1015:9

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

            trace_function = sys.gettrace()
            sys.settrace(None)
            assert self.curframe is not None
            globals = self.curframe.f_globals
    likely benign LLM, confidence 0.90 Debugger temporarily clears the trace function during a recursive debug session.
    Reasoning

    sys.settrace(None) temporarily disables tracing while the recursive debugger runs, a standard pdb pattern. Nothing here is hidden or malicious.

  13. info critical → info by review frame-introspection IPython/core/debugger.py:1027:9

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

            self.message("LEAVING RECURSIVE DEBUGGER")
            sys.settrace(trace_function)
            self.lastcmd = p.lastcmd
    likely benign LLM, confidence 0.90 Debugger restores the saved trace function on leaving a recursive session.
    Reasoning

    This restores the previously saved trace function after leaving a recursive debugger, which is standard pdb bookkeeping.

  14. info critical → info by review frame-introspection IPython/core/debugger.py:1445:13

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

                self.do_quit("")
                sys.settrace(None)
                self.quitting = False
                raise
    likely benign LLM, confidence 0.90 Debugger clears the trace function when quitting.
    Reasoning

    This clears the trace function on quit in the debugger, matching pdb's own quit logic. It is legitimate tracing control.

  15. info critical → info by review frame-introspection IPython/core/debugger.py:1472:28

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

            pdb.message(header)
        pdb.set_trace(frame or sys._getframe().f_back)
    likely benign LLM, confidence 0.90 Module-level set_trace helper defaults to the caller's frame.
    Reasoning

    This is the module-level set_trace convenience function, which defaults to the caller's frame. It is the documented debugger entry point.

  16. info warn → info by review dynamic-execution IPython/core/debugger_backport.py:79:16

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

    
            code = compile(source, "<string>", "exec")
            if not any(isinstance(const, CodeType) for const in code.co_consts):
                return False
    likely benign LLM, confidence 0.90 Compiles source in a backport helper to inspect its constants.
    Reasoning

    This backport checks whether source contains nested code objects, which is a compile-and-inspect step in debugger support code. It does not run the code.

  17. info warn → info by review dynamic-execution IPython/core/debugger_backport.py:91:13

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

            try:
                compile(source, "<string>", "eval")
            except SyntaxError:
                pass
    likely benign LLM, confidence 0.90 Syntax-check compile of an expression inside a try block.
    Reasoning

    This is a syntax-check compile in a try/except that only tests whether an expression parses. It has no execution or hidden behaviour.

  18. info warn → info by review dynamic-execution IPython/core/debugger_backport.py:130:13

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

            try:
                exec(source_with_closure, {}, ns)
            except Exception:
                return False
    likely benign LLM, confidence 0.88 Executes debugged source in a closure context for expression evaluation.
    Reasoning

    This executes user-debugged source with closure cells so that the debugger can evaluate expressions in a frame context. This is the purpose of the backport.

  19. info warn → info by review dynamic-execution IPython/core/debugger_backport.py:138:13

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

            try:
                exec(code, globals, locals_copy, closure=cells)
            except Exception:
                return False
    likely benign LLM, confidence 0.88 Executes compiled debugged code in the frame's namespace.
    Reasoning

    This runs the compiled code object in the debugged frame's globals with closure cells, mirroring the interpreter's exec behaviour. It is expected in a debugger backport.

  20. info warn → info by review dynamic-execution IPython/core/debugger_backport.py:200:21

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

                    if not self._exec_in_closure(buffer, globals, locals):
                        exec(code, globals, locals)
                finally:
                    sys.stdout = save_stdout
    likely benign LLM, confidence 0.90 Debugger fallback executes user-entered statements in the current frame.
    Reasoning

    This is the debugger's fallback exec of user-entered statements in the current frame. It is the purpose of the debugger's command line.

  21. info whitespace-anomaly IPython/core/display.py:23:1

    file mixes tab and space indentation (9 tab-indented and 967 space-indented lines) (raw pass, confidence 0.40)

    if TYPE_CHECKING:
        from collections.abc import Callable
  22. info warn → info by review dynamic-execution IPython/core/guarded_eval.py:467:16

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

        if context.evaluation == "dangerous":
            return eval(code, context.globals, context.locals)
    
        node = ast.parse(code, mode="exec")
    likely benign LLM, confidence 0.85 Opt-in unrestricted eval branch in IPython's guarded evaluator.
    Reasoning

    This eval runs only when the context's evaluation mode is explicitly 'dangerous', an opt-in mode. Otherwise the module uses a restricted AST-based evaluator. The eval is intentional and gated.

  23. info critical → info by review dynamic-execution IPython/core/hooks.py:97:12

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

        import subprocess
        proc = subprocess.Popen('{} {} {}'.format(editor, linemark, filename),
                                shell=True)
        if wait and proc.wait() != 0:
    likely benign LLM, confidence 0.80 Editor hook launches the user-configured editor command through the shell.
    Reasoning

    This is IPython's editor hook, which runs the user's configured editor command through the shell with the filename substituted. The shell use is a known design choice, and the command comes from local configuration, not from untrusted input. Quoting of the filename is a minor concern.

  24. info critical → info by review frame-introspection IPython/core/interactiveshell.py:1657:18

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

                vdict = {}
                cf = sys._getframe(1)
                for name in vlist:
                    try:
    likely benign LLM, confidence 0.97 Caller frame introspection in IPython's variable-fetch helper.
    Reasoning

    sys._getframe used to fetch caller namespaces for the %who/magic variable lookup in IPython's shell; this is standard IPython behavior, not anti-analysis. The critical severity reflects a naive heuristic pairing with exec/eval, which are core to an interactive shell.

  25. info warn → info by review dynamic-execution IPython/core/interactiveshell.py:1660:35

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

                    try:
                        vdict[name] = eval(name, cf.f_globals, cf.f_locals)
                    except Exception:
                        print('Could not get variable %s from %s' %
    likely benign LLM, confidence 0.96 eval of user-supplied variable names in caller namespace.
    Reasoning

    eval of a variable name against the caller's globals and locals is the intended mechanism of IPython's push/variable retrieval for user-named variables inside an interactive shell.

  26. info warn → info by review dynamic-execution IPython/core/interactiveshell.py:1855:19

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

            if not found and oname_head in ["''",'""','[]','{}','()']:
                obj = eval(oname_head)
                found = True
                ospace = 'Interactive'
    likely benign LLM, confidence 0.96 eval restricted to a literal whitelist of empty-literal tokens.
    Reasoning

    Evaluates only a fixed whitelist of literal empty-container/string tokens ('' , "", [], {}, ()) for object info lookup; the non-literal flag is a false positive with no hostile input path.

  27. info critical → info by review frame-introspection IPython/core/interactiveshell.py:2602:16

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

            """
            return sys._getframe(stack_depth + 1).f_locals
    
        def run_cell_magic(self, magic_name, line, cell):
    likely benign LLM, confidence 0.95 Caller frame locals retrieval for shell namespace handling.
    Reasoning

    Returns caller locals via sys._getframe(stack_depth+1) for IPython's local namespace lookup; standard shell introspection, not evasion.

  28. info critical → info by review dynamic-execution IPython/core/interactiveshell.py:2762:26

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

                    try:
                        ec = os.system(cmd)
                    except KeyboardInterrupt:
                        print('\n' + self.get_exception_only(), file=sys.stderr)
    likely benign LLM, confidence 0.93 os.system invoked for user-typed '!' shell escapes.
    Reasoning

    os.system with a runtime command is the purpose of IPython's '!' system-shell escape, which the user types interactively. This is expected behavior for the shell, though it is a powerful primitive.

  29. info critical → info by review dynamic-execution IPython/core/interactiveshell.py:2780:22

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

                    import subprocess
                    ec = subprocess.call(cmd, shell=True, executable=executable)
                except KeyboardInterrupt:
                    # intercept control-C; a long traceback is not useful here
    likely benign LLM, confidence 0.93 Shell-enabled subprocess call for user-entered system commands.
    Reasoning

    subprocess.call with shell=True implements IPython's system_piped escape for user-entered commands; expected interactive functionality rather than a hidden dropper.

  30. info warn → info by review dynamic-execution IPython/core/interactiveshell.py:2971:47

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

                try:
                    value = self._format_user_obj(eval(expr, global_ns, user_ns))
                except:
                    value = self._user_obj_error()
    likely benign LLM, confidence 0.95 eval of user expressions in the shell namespace.
    Reasoning

    eval of user expression for the ev/user-expression feature (IPython's run_cell user_expressions), guarded by a bare except; intended behavior of an interactive kernel.

  31. info warn → info by review dynamic-execution IPython/core/interactiveshell.py:2984:13

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

            with self.builtin_trap:
                exec(cmd, self.user_global_ns, self.user_ns)
    
        def ev(self, expr):
    likely benign LLM, confidence 0.95 exec of user command string in the shell namespace.
    Reasoning

    exec of a command string in the user namespace is the core of IPython's ex/run mechanism; expected for an interpreter and not hidden or encoded.

  32. info warn → info by review dynamic-execution IPython/core/interactiveshell.py:2992:20

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

            with self.builtin_trap:
                return eval(expr, self.user_global_ns, self.user_ns)
    
        def safe_execfile(self, fname, *where, exit_ignore=False, raise_exceptions=False, shell_futures=False):
    likely benign LLM, confidence 0.95 eval helper evaluating expressions in the user namespace.
    Reasoning

    Returns eval of an expression in user namespaces, the documented ev() helper of the shell; no obfuscation involved.

  33. info warn → info by review dynamic-execution IPython/core/interactiveshell.py:3040:17

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

                    compiler = compiler or compile
                    exec(compiler(f.read(), fname, "exec"), glob, loc)
    
            with prepended_to_syspath(dname), self.builtin_trap:
    likely benign LLM, confidence 0.95 Compile and exec of a user-requested file.
    Reasoning

    safe_execfile compiles and executes a file the user explicitly asked to run; standard IPython file execution.

  34. info warn → info by review dynamic-execution IPython/core/interactiveshell.py:3821:27

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

                    if async_:
                        await eval(code_obj, self.user_global_ns, self.user_ns)
                    else:
                        exec(code_obj, self.user_global_ns, self.user_ns)
    likely benign LLM, confidence 0.95 Execution of compiled cell code in the shell.
    Reasoning

    Executes compiled user cell code (async or sync) in the shell's namespaces; core interpreter behavior.

  35. info warn → info by review dynamic-execution IPython/core/interactiveshell.py:3823:21

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

                    else:
                        exec(code_obj, self.user_global_ns, self.user_ns)
                finally:
                    # Reset our crash handler in place
    likely benign LLM, confidence 0.95 Synchronous exec of compiled cell code.
    Reasoning

    Sync branch of the same cell-execution path; core interpreter functionality with no hidden payload.

  36. info critical → info by review frame-introspection IPython/core/interactiveshell.py:3995:21

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

            try:
                frame = sys._getframe(depth+1)
            except ValueError:
                # This is thrown if there aren't that many frames on the stack,
    likely benign LLM, confidence 0.95 Caller frame retrieval with depth guard in IPython utilities.
    Reasoning

    Caller frame lookup with a ValueError guard for shallow stacks, used by IPython's namespace-depth utilities; ordinary introspection.

  37. info warn → info by review dynamic-execution IPython/core/interactiveshell.py:4155:23

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

            try:                                              # User namespace
                codeobj = eval(target, self.user_ns)
            except Exception as e:
                raise ValueError(("'%s' was not found in history, as a file, url, "
    likely benign LLM, confidence 0.85 eval of a user-supplied target expression in IPython's user namespace during history lookup.
    Reasoning

    eval of a target name in the user namespace is the documented behavior of the %edit/%run-style history lookup; the user is the one typing the expression in an interactive shell.

  38. info unicode-homoglyph IPython/core/latex_symbols.py:186:17

    identifier `Α` contains homoglyph candidates: Α (0391)→A (in string/comment) (raw pass, confidence 0.35)

        "\\strike": "̶",
        "\\Alpha": "Α",
        "\\Beta": "Β",
        "\\Gamma": "Γ",
  39. info unicode-homoglyph IPython/core/latex_symbols.py:187:16

    identifier `Β` contains homoglyph candidates: Β (0392)→B (in string/comment) (raw pass, confidence 0.35)

        "\\Alpha": "Α",
        "\\Beta": "Β",
        "\\Gamma": "Γ",
        "\\Delta": "Δ",
  40. info unicode-homoglyph IPython/core/latex_symbols.py:190:19

    identifier `Ε` contains homoglyph candidates: Ε (0395)→E (in string/comment) (raw pass, confidence 0.35)

        "\\Delta": "Δ",
        "\\Epsilon": "Ε",
        "\\Zeta": "Ζ",
        "\\Eta": "Η",
  41. info unicode-homoglyph IPython/core/latex_symbols.py:192:15

    identifier `Η` contains homoglyph candidates: Η (0397)→H (in string/comment) (raw pass, confidence 0.35)

        "\\Zeta": "Ζ",
        "\\Eta": "Η",
        "\\Theta": "Θ",
        "\\Iota": "Ι",
  42. info unicode-homoglyph IPython/core/latex_symbols.py:195:17

    identifier `Κ` contains homoglyph candidates: Κ (039A)→K (in string/comment) (raw pass, confidence 0.35)

        "\\Iota": "Ι",
        "\\Kappa": "Κ",
        "\\Lambda": "Λ",
        "\\Xi": "Ξ",
  43. info unicode-homoglyph IPython/core/latex_symbols.py:199:15

    identifier `Ρ` contains homoglyph candidates: Ρ (03A1)→P (in string/comment) (raw pass, confidence 0.35)

        "\\Pi": "Π",
        "\\Rho": "Ρ",
        "\\Sigma": "Σ",
        "\\Tau": "Τ",
  44. info unicode-homoglyph IPython/core/latex_symbols.py:201:15

    identifier `Τ` contains homoglyph candidates: Τ (03A4)→T (in string/comment) (raw pass, confidence 0.35)

        "\\Sigma": "Σ",
        "\\Tau": "Τ",
        "\\Upsilon": "Υ",
        "\\Phi": "Φ",
  45. info unicode-homoglyph IPython/core/latex_symbols.py:202:19

    identifier `Υ` contains homoglyph candidates: Υ (03A5)→Y (in string/comment) (raw pass, confidence 0.35)

        "\\Tau": "Τ",
        "\\Upsilon": "Υ",
        "\\Phi": "Φ",
        "\\Chi": "Χ",
  46. info unicode-homoglyph IPython/core/latex_symbols.py:204:15

    identifier `Χ` contains homoglyph candidates: Χ (03A7)→X (in string/comment) (raw pass, confidence 0.35)

        "\\Phi": "Φ",
        "\\Chi": "Χ",
        "\\Psi": "Ψ",
        "\\Omega": "Ω",
  47. info unicode-homoglyph IPython/core/latex_symbols.py:207:17

    identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        "\\Omega": "Ω",
        "\\alpha": "α",
        "\\beta": "β",
        "\\gamma": "γ",
  48. info unicode-homoglyph IPython/core/latex_symbols.py:212:15

    identifier `η` contains homoglyph candidates: η (03B7)→n (in string/comment) (raw pass, confidence 0.35)

        "\\zeta": "ζ",
        "\\eta": "η",
        "\\theta": "θ",
        "\\iota": "ι",
  49. info unicode-homoglyph IPython/core/latex_symbols.py:215:17

    identifier `κ` contains homoglyph candidates: κ (03BA)→k (in string/comment) (raw pass, confidence 0.35)

        "\\iota": "ι",
        "\\kappa": "κ",
        "\\lambda": "λ",
        "\\mu": "μ",
  50. info unicode-homoglyph IPython/core/latex_symbols.py:218:14

    identifier `ν` contains homoglyph candidates: ν (03BD)→v (in string/comment) (raw pass, confidence 0.35)

        "\\mu": "μ",
        "\\nu": "ν",
        "\\xi": "ξ",
        "\\pi": "π",
  51. info unicode-homoglyph IPython/core/latex_symbols.py:221:15

    identifier `ρ` contains homoglyph candidates: ρ (03C1)→p (in string/comment) (raw pass, confidence 0.35)

        "\\pi": "π",
        "\\rho": "ρ",
        "\\varsigma": "ς",
        "\\sigma": "σ",
  52. info unicode-homoglyph IPython/core/latex_symbols.py:263:14

    identifier `Μ` contains homoglyph candidates: Μ (039C)→M (in string/comment) (raw pass, confidence 0.35)

        "\\not": "̸",
        "\\Mu": "Μ",
        "\\Nu": "Ν",
        "\\Omicron": "Ο",
  53. info unicode-homoglyph IPython/core/latex_symbols.py:264:14

    identifier `Ν` contains homoglyph candidates: Ν (039D)→N (in string/comment) (raw pass, confidence 0.35)

        "\\Mu": "Μ",
        "\\Nu": "Ν",
        "\\Omicron": "Ο",
        "\\omicron": "ο",
  54. info unicode-homoglyph IPython/core/latex_symbols.py:265:19

    identifier `Ο` contains homoglyph candidates: Ο (039F)→O (in string/comment) (raw pass, confidence 0.35)

        "\\Nu": "Ν",
        "\\Omicron": "Ο",
        "\\omicron": "ο",
        "\\varbeta": "ϐ",
  55. info unicode-homoglyph IPython/core/latex_symbols.py:266:19

    identifier `ο` contains homoglyph candidates: ο (03BF)→o (in string/comment) (raw pass, confidence 0.35)

        "\\Omicron": "Ο",
        "\\omicron": "ο",
        "\\varbeta": "ϐ",
        "\\oldKoppa": "Ϙ",
  56. info warn → info by review frame-introspection IPython/core/magic.py:249:29

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

            # Find get_ipython() in the caller's namespace
            caller: FrameType = sys._getframe(1)
            get_ipython: Callable[[], InteractiveShell] | None = None
            for ns in ["f_locals", "f_globals", "f_builtins"]:
    likely benign LLM, confidence 0.90 Uses sys._getframe to locate get_ipython in the caller's namespace.
    Reasoning

    Reading the caller's frame to find get_ipython() is a standard IPython mechanism for locating the shell; it is not hiding behavior.

  57. info warn → info by review frame-introspection IPython/core/magic.py:947:18

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

            # inject default options at the beginning of the input line
            caller = sys._getframe(1).f_code.co_name
            arg_str = "{} {}".format(self.options_table.get(caller, ""), arg_str)
    likely benign LLM, confidence 0.90 Reads the caller's code name to inject default magic options.
    Reasoning

    Reading the caller's function name to look up default magic options is a benign introspection pattern.

  58. info warn → info by review dynamic-attribute IPython/core/magics/__init__.py:66:11

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

    
        obj = globals()[name] = getattr(import_module(module_name), name)
        return obj
    likely benign LLM, confidence 0.90 Lazily imports a magic function by name and caches it in module globals.
    Reasoning

    Lazy-loading a magic by importing its module and caching the attribute in globals is a normal deferred-import pattern.

  59. info warn → info by review dynamic-execution IPython/core/magics/code.py:469:28

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

                        # print('*** args',args,'type',type(args))  # dbg
                        data = eval(args, shell.user_ns)
                        if not isinstance(data, str):
                            raise DataIsObject
    likely benign LLM, confidence 0.85 Evaluates user-supplied argument expression in the user namespace.
    Reasoning

    The eval evaluates an expression the user typed in the %paste/%edit-style magic within their own session; this is the intended feature.

  60. info critical → info by review dynamic-execution IPython/core/magics/config.py:137:9

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

            cfg = Config()
            exec("cfg."+line, self.shell.user_ns, locals())
    
            for configurable in configurables:
    likely benign LLM, confidence 0.80 exec of a config assignment built from the user's %config argument.
    Reasoning

    exec of 'cfg.'+line builds a statement from the user's %config command line in the user's own shell. Severity is critical but the input is the interactive user's own text, so it is the expected config-magic design rather than an attack.

  61. info critical → info by review frame-introspection IPython/core/magics/execution.py:991:21

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

                    finally:
                        sys.settrace(trace)
    
                # Perform proper cleanup of the session in case if
    likely benign LLM, confidence 0.80 Restores the trace function after running code under a profiler.
    Reasoning

    sys.settrace is used to restore the tracer after profiling/debugging in %prun or similar; the co-occurrence with exec/eval is just the magic's own execution code, not anti-analysis.

  62. info warn → info by review dynamic-execution IPython/core/magics/execution.py:1225:9

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

    
            exec(code, glob, ns)
            timer.inner = ns["inner"]
    likely benign LLM, confidence 0.90 exec of the generated timeit inner function template.
    Reasoning

    exec of timeit's generated template source compiled from the user's statement is the documented timeit implementation.

  63. info warn → info by review dynamic-execution IPython/core/magics/execution.py:1412:23

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

                try:
                    out = eval(code, glob, local_ns)
                except KeyboardInterrupt as e:
                    captured_exception = e
    likely benign LLM, confidence 0.90 eval of the user's timed code in a local namespace.
    Reasoning

    eval of user-entered code in %time/%timeit is the intended behavior of running the user's own statements.

  64. info warn → info by review dynamic-execution IPython/core/magics/execution.py:1426:17

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

                try:
                    exec(code, glob, local_ns)
                    out = None
                    # multi-line %%time case
    likely benign LLM, confidence 0.90 exec of the user's timed statement in a local namespace.
    Reasoning

    exec of the user's timed statement in %time is the intended purpose of the magic.

  65. info warn → info by review dynamic-execution IPython/core/magics/execution.py:1431:27

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

                        code_2 = self.shell.compile(expr_val, source, 'eval')
                        out = eval(code_2, glob, local_ns)
                except KeyboardInterrupt as e:
                    captured_exception = e
    likely benign LLM, confidence 0.90 Compiles and evals the user's timed expression.
    Reasoning

    Compiling and evaluating the user's expression for %time output is the intended behavior.

  66. info warn → info by review dynamic-execution IPython/core/magics/history.py:297:23

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

            try:                        # Variable in user namespace
                cmd = str(eval(arg, self.shell.user_ns))
            except Exception:           # Search for term in history
                histlines = self.shell.history_manager.search("*"+arg+"*")
    likely benign LLM, confidence 0.85 Evaluates a user argument in the user namespace to find a variable's value.
    Reasoning

    eval of a user-supplied variable name in the user namespace for %history search is the documented feature.

  67. info critical → info by review dynamic-execution IPython/core/page.py:202:24

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

                        # tmpfile needs to be closed for windows
                        if os.system(cmd):
                            retval = 1
                        else:
    likely benign LLM, confidence 0.85 Runs the configured pager command via os.system.
    Reasoning

    os.system on the pager command is the legitimate way IPython pages output through the user's configured pager; the command is user configuration, not attacker-supplied.

  68. info critical → info by review dynamic-execution IPython/core/page.py:213:24

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

                    import subprocess
                    proc = subprocess.Popen(
                        pager_cmd,
                        shell=True,
    likely benign LLM, confidence 0.85 Launches the configured pager through a shell.
    Reasoning

    Popen with shell=True runs the user's configured pager command, which is the expected pager invocation in IPython's page module.

  69. info warn → info by review decoder-import-with-exec IPython/core/pylabtools.py:423:5

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

              )
        exec(s, user_ns)
    
        if import_all:
    likely benign LLM, confidence 0.85 Executes generated import statements to set up pylab in the user namespace.
    Reasoning

    exec runs a string built from matplotlib/numpy import statements into the user namespace, as IPython's pylab setup does. The binascii import is incidental and the snippet shows no decoding of hidden payloads.

  70. info warn → info by review dynamic-execution IPython/core/pylabtools.py:423:5

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

              )
        exec(s, user_ns)
    
        if import_all:
    likely benign LLM, confidence 0.85 exec of an internally built import string in pylab setup.
    Reasoning

    The exec argument is an internally generated import string for pylab setup, the expected IPython behaviour for a magic like %pylab.

  71. info warn → info by review dynamic-execution IPython/core/pylabtools.py:428:9

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

                 "from numpy import *\n")
            exec(s, user_ns)
    
        # IPython symbols to add
    likely benign LLM, confidence 0.88 exec of a fixed numpy import string during pylab setup.
    Reasoning

    Same pylab setup path; the string is a fixed import line such as 'from numpy import *' plus generated text, with no external input.

  72. info unicode-homoglyph IPython/core/tips.py:105:86

    identifier `α` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

            [
                "You can use LaTeX or Unicode completion, `\\alpha<tab>` will insert the α symbol.",
                "You can find how to type a LaTeX symbol by back-completing it, eg `\\θ<tab>` will expand to `\\theta`.",
  73. info warn → info by review decoder-import-with-exec IPython/extensions/deduperreload/deduperreload.py:471:37

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

                    for func_ast in func_asts:
                        compiled_code = compile(
                            func_ast, filename, mode="exec", dont_inherit=True
                        )
    likely benign LLM, confidence 0.85 Compiles AST of reloaded module source for autoreload.
    Reasoning

    The deduperreload extension compiles new AST of edited source files on autoreload. Pickle import here is not a payload decoder; the compile input is the user's own parsed source.

  74. info warn → info by review dynamic-execution IPython/extensions/deduperreload/deduperreload.py:471:37

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

                    for func_ast in func_asts:
                        compiled_code = compile(
                            func_ast, filename, mode="exec", dont_inherit=True
                        )
    likely benign LLM, confidence 0.90 compile of reparsed module AST for hot reloading.
    Reasoning

    compile of parsed AST from the user's own module source during autoreload is the expected mechanism.

  75. info warn → info by review dynamic-execution IPython/extensions/deduperreload/deduperreload.py:474:21

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

                        )
                        exec(compiled_code, global_env, local_env)
                        # local_env contains the function exec'd from  new version of function
                        if is_method:
    likely benign LLM, confidence 0.90 exec of recompiled function definitions for autoreload.
    Reasoning

    Executes freshly compiled code of a changed function into a local env to replace the old definition, which is the extension's documented purpose.

  76. info warn → info by review dynamic-execution IPython/extensions/deduperreload/deduperreload.py:506:17

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

                else:
                    exec(
                        ast.unparse(new_ast_def),
                        ns.__dict__ | namespace_to_check.__dict__,
    likely benign LLM, confidence 0.90 exec of unparsed changed definition during reload.
    Reasoning

    Executes unparsed AST of a changed definition in the module namespace, consistent with hot reloading of source the user edited.

  77. info warn → info by review dynamic-execution IPython/extensions/deduperreload/deduperreload.py:523:13

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

                local_env_class: dict[str, Any] = {}
                exec(
                    ast.unparse(class_ast_node),
                    ns.__dict__ | namespace_to_check.__dict__,
    likely benign LLM, confidence 0.90 exec of unparsed changed class definition during reload.
    Reasoning

    Same reload mechanism applied to a class node; the source is the user's own module code.

  78. info critical → info by review frame-introspection IPython/lib/backgroundjobs.py:175:25

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

                if not args:
                    frame = sys._getframe(1)
                    glob, loc = frame.f_globals, frame.f_locals
                elif len(args)==1:
    likely benign LLM, confidence 0.80 Reads the caller's frame globals and locals as default namespace for a background job.
    Reasoning

    sys._getframe(1) is used to fetch the caller's globals and locals when BackgroundJob is given no namespace, a common pattern. The critical severity is overstated; the sys.exit/exec co-occurrence is just elsewhere in the file.

  79. info warn → info by review dynamic-execution IPython/lib/backgroundjobs.py:454:21

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

            # fail immediately if the given expression can't be compiled
            self.code = compile(expression,'<BackgroundJob compilation>','eval')
    
            glob = {} if glob is None else glob
    likely benign LLM, confidence 0.90 Compiles a user-supplied expression for a background job.
    Reasoning

    BackgroundJob is a documented feature that runs a user-supplied expression in a thread. Compiling it early to fail fast is the intended design, not hidden execution.

  80. info warn → info by review dynamic-execution IPython/lib/backgroundjobs.py:464:16

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

        def call(self):
            return eval(self.code,self.glob,self.loc)
    likely benign LLM, confidence 0.90 Evaluates the user's expression for a background job.
    Reasoning

    eval of the precompiled user expression in a background thread is the documented purpose of the class.

  81. info warn → info by review dynamic-execution IPython/lib/demo.py:449:9

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

    
            exec(source, self.user_ns)
    
        def __call__(self,index=None):
    likely benign LLM, confidence 0.90 Executes demo block source in the user namespace.
    Reasoning

    IPython Demo runs the source of a demo script the user chose to run, executing it in the user namespace by design.

  82. info critical → info by review dynamic-execution IPython/lib/editorhooks.py:53:16

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

                cmd = shlex.split(cmd)
            proc = subprocess.Popen(cmd, shell=True)
            if proc.wait() != 0:
                raise TryNext()
    likely benign LLM, confidence 0.78 Launches the user's configured editor command through a shell.
    Reasoning

    shell=True is used with an editor command that comes from the user's configured editor setting, not from remote or file-embedded input. This is a risky pattern but matches the intended user-configured editor launch.

  83. info warn → info by review dynamic-execution IPython/sphinxext/custom_doctests.py:79:22

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

        if s.startswith('['):
            a = np.array(eval(s), dtype=float)
        else:
            # Assume its a regular float. Force 1D so we can index into it.
    likely benign LLM, confidence 0.80 Evaluates bracketed array text in a Sphinx doctest helper.
    Reasoning

    eval is applied to array literal text from doctest source in the docs build, a narrow use for parsing bracketed number lists. The input is developer-written doc text.

  84. info warn → info by review frame-introspection IPython/terminal/debugger.py:169:38

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

        """
        TerminalPdb().set_trace(frame or sys._getframe().f_back)
    likely benign LLM, confidence 0.95 Uses the caller frame when starting the debugger trace.
    Reasoning

    Falling back to the caller frame for set_trace is the standard debugger idiom; there is no evasion or hidden behaviour.

  85. info warn → info by review frame-introspection IPython/terminal/embed.py:216:21

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

            if not clid:
                frame = sys._getframe(1)
                clid = '{}:{}'.format(frame.f_code.co_filename, frame.f_lineno)
            self._init_location_id = clid
    likely benign LLM, confidence 0.95 Reads caller frame filename and line number to build an init location id for the embedded IPython shell.
    Reasoning

    sys._getframe(1) is used to record the caller's file and line as a location identifier for embedded shell instances; read-only introspection with no exec or network behavior.

  86. info warn → info by review frame-introspection IPython/terminal/embed.py:272:21

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

            if not clid:
                frame = sys._getframe(1)
                clid = '{}:{}'.format(frame.f_code.co_filename, frame.f_lineno)
            self._call_location_id = clid
    likely benign LLM, confidence 0.95 Reads caller frame metadata to build a call location id for the embedded shell.
    Reasoning

    Same benign pattern as the other embed.py finding: caller frame metadata is read to label a call location.

  87. info warn → info by review frame-introspection IPython/terminal/embed.py:343:26

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

                and self.default_user_namespaces):
                call_frame = sys._getframe(stack_depth).f_back
    
                if local_ns is None:
    likely benign LLM, confidence 0.93 Gets a stack frame at a given depth to pick up caller namespaces for the embedded shell.
    Reasoning

    Uses sys._getframe with a stack depth to obtain the caller's namespaces when embedding, a standard debugging/embedding feature in IPython.

  88. info warn → info by review frame-introspection IPython/terminal/embed.py:480:13

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

            cls.clear_instance()
        frame = sys._getframe(1)
        shell = InteractiveShellEmbed.instance(_init_location_id='{}:{}'.format(
            frame.f_code.co_filename, frame.f_lineno), **kwargs)
    likely benign LLM, confidence 0.95 Reads the calling frame's location to initialize the embedded shell singleton.
    Reasoning

    Reads caller frame filename and line to construct the shell instance's init location id; purely informational.

  89. info warn → info by review dynamic-execution IPython/terminal/magics.py:213:13

    `os.system` called with a literal shell command (ast pass, confidence 0.70)

                """
                os.system("cls")
    likely benign LLM, confidence 0.97 Runs the fixed command 'cls' to clear the terminal screen.
    Reasoning

    os.system with a fixed literal 'cls' is the standard Windows clear-screen command inside a %clear magic; no external input.

  90. info critical → info by review builtins-write IPython/testing/plugin/pytest_ipdoctest.py:367:17

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

                if had_underscore_value:
                    setattr(builtins, "_", underscore_original_value)
                elif hasattr(builtins, "_"):
                    delattr(builtins, "_")
    likely benign LLM, confidence 0.85 Saves and restores the builtins '_' name around doctest execution.
    Reasoning

    Restores or removes the builtins '_' value after doctest runs so the doctest's underscore handling does not leak; this is a scoped, restorative patch used in test tooling, not persistent malicious tampering, though it does mutate builtins.

  91. info warn → info by review frame-introspection IPython/utils/frame.py:28:9

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

        """Returns (module, locals) of the function `depth` frames away from the caller"""
        f = sys._getframe(depth + 1)
        global_ns = f.f_globals
        module = sys.modules[global_ns['__name__']]
    likely benign LLM, confidence 0.93 Returns module and locals of a caller frame at a given depth.
    Reasoning

    Frame introspection to fetch the module and locals of an ancestor frame; a documented helper for namespace lookups, no exec or network.

  92. info critical → info by review dynamic-import IPython/utils/importstring.py:33:18

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

            package, obj = parts
            module = __import__(package, fromlist=[obj])
            try:
                pak = getattr(module, obj)
    likely benign LLM, confidence 0.85 Imports a module from a dotted string name passed in by the caller.
    Reasoning

    Dynamic import of a user-supplied dotted path is the documented purpose of import_item in IPython; it is a generic plugin/loader primitive, and the input comes from configuration by design, not from obfuscation.

  93. info critical → info by review dynamic-import IPython/utils/importstring.py:41:16

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

            # called with un-dotted string
            return __import__(parts[0])
    likely benign LLM, confidence 0.85 Imports a top-level module given as a string name.
    Reasoning

    Same import_item helper importing a top-level module by name; expected behavior for a string-based import utility.

  94. info warn → info by review dynamic-execution IPython/utils/terminal.py:31:9

    `os.system` called with a literal shell command (ast pass, confidence 0.70)

        def _term_clear():
            os.system('clear')
    elif sys.platform == 'win32':
        def _term_clear():
    likely benign LLM, confidence 0.95 Runs the fixed 'clear' command to clear the terminal on Unix.
    Reasoning

    Fixed literal 'clear' command for POSIX terminal clearing; no untrusted input.

  95. info warn → info by review dynamic-execution IPython/utils/terminal.py:34:9

    `os.system` called with a literal shell command (ast pass, confidence 0.70)

        def _term_clear():
            os.system('cls')
    else:
        def _term_clear():
    likely benign LLM, confidence 0.95 Runs the fixed 'cls' command to clear the terminal on Windows.
    Reasoning

    Fixed literal 'cls' command for Windows terminal clearing; no untrusted input.

  96. info warn → info by review dynamic-execution IPython/utils/text.py:450:13

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

        def get_field(self, name: str, args: Any, kwargs: Any) -> tuple[Any, str]:
            v = eval(name, kwargs, kwargs)
            return v, name
    likely benign LLM, confidence 0.80 Evaluates a format-string field expression against provided keyword arguments.
    Reasoning

    eval on a format field name is part of IPython's documented EvalFormatter feature for evaluating expressions in format strings; it is intentional but does execute code from the template, so it is a real risk surface rather than hidden malice.

  97. info warn → info by review dynamic-execution IPython/utils/text.py:505:23

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

                    # to be formatted
                    obj = eval(field_name, dict(kwargs))
    
                    # do any conversion on the resulting object
    likely benign LLM, confidence 0.80 Evaluates a format field expression within the formatter's kwargs.
    Reasoning

    Same EvalFormatter design: field expressions from the format string are evaluated by intent; expected for this feature, not obfuscation.

Reproduce This Scan

Run disclude locally to verify. These commands scan the published file; the "new in this release" marks come from comparing it with the previous release's file, which they don't repeat. 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.3.0
curl -fsSL -o ipython-9.18.0-py3-none-any.whl https://files.pythonhosted.org/packages/55/7e/61834f817d193fe48ebe4bf1f9bb24c145143423db019897387c30c8f80a/ipython-9.18.0-py3-none-any.whl
printf '%s  %s\n' d9b8e19267e811cafbc9d72e794a130c3fc60518108d20f5e1f05dae74f619ec ipython-9.18.0-py3-none-any.whl | shasum -a 256 -c -
unzip -q ipython-9.18.0-py3-none-any.whl -d pkg
disclude scan --untrusted --severity info pkg