Skip to content

Python 3.13.0 REPL loads local files unexpectedly, causing conflicts and security issues #125140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
aleksa opened this issue Oct 8, 2024 · 11 comments
Labels
3.13 bugs and security fixes 3.14 bugs and security fixes topic-repl Related to the interactive shell type-bug An unexpected behavior, bug, or error type-security A security issue

Comments

@aleksa
Copy link

aleksa commented Oct 8, 2024

Bug report

Bug description:

Description

When starting the Python 3.13.0 REPL in a directory containing a file named code.py, the REPL attempts to load this local file instead of the standard library code module. This causes conflicts and errors when initializing the interactive environment. This is also a major security issue.

Steps to Reproduce

  1. Create a directory and navigate to it
  2. Create a file named code.py in this directory
  3. Ensure Python 3.13.0 is installed (e.g., using pyenv)
  4. Start the Python 3.13.0 REPL in this directory

Expected Behavior

The Python REPL should start normally, using the standard library code module for its interactive features.

Actual Behavior

The REPL fails to initialize properly, producing an error message indicating that it's attempting to use the local code.py file instead of the standard library module:

aleksa@aleksa:~/testing13$ python
Python 3.13.0 (main, Oct  8 2024, 16:45:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
Failed calling sys.__interactivehook__
Traceback (most recent call last):
  File "<frozen site>", line 498, in register_readline
  File "/home/aleksa/.pyenv/versions/3.13.0/lib/python3.13/_pyrepl/readline.py", line 39, in <module>
    from . import commands, historical_reader
  File "/home/aleksa/.pyenv/versions/3.13.0/lib/python3.13/_pyrepl/historical_reader.py", line 26, in <module>
    from .reader import Reader
  File "/home/aleksa/.pyenv/versions/3.13.0/lib/python3.13/_pyrepl/reader.py", line 32, in <module>
    from . import commands, console, input
  File "/home/aleksa/.pyenv/versions/3.13.0/lib/python3.13/_pyrepl/console.py", line 153, in <module>
    class InteractiveColoredConsole(code.InteractiveConsole):
                                    ^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: module 'code' has no attribute 'InteractiveConsole' (consider renaming '/home/aleksa/testing13/code.py' since it has the same name as the standard library module named 'code' and the import system gives it precedence)
warning: can't use pyrepl: module 'code' has no attribute 'InteractiveConsole' (consider renaming '/home/aleksa/testing13/code.py' since it has the same name as the standard library module named 'code' and the import system gives it precedence)
>>>

Additional Context

  • This behavior is not observed in Python 3.12.7
  • The issue seems to be related to how Python 3.13.0 handles module imports in the REPL initialization process

System Information

  • OS: Linux (Ubuntu 22.04)
  • Python version: 3.13.0
  • Installation method: pyenv

Possible Solution

The REPL initialization process should be modified to ensure it uses the standard library code module, regardless of local files in the current directory.

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

@aleksa aleksa added the type-bug An unexpected behavior, bug, or error label Oct 8, 2024
@aleksa aleksa changed the title Python 3.13.0 REPL loads local files unexpectedly, causing conflicts Python 3.13.0 REPL loads local files unexpectedly, causing conflicts and security issues Oct 8, 2024
@tomasr8 tomasr8 added the topic-repl Related to the interactive shell label Oct 8, 2024
@skirpichev skirpichev added the 3.13 bugs and security fixes label Oct 8, 2024
@tomasr8
Copy link
Member

tomasr8 commented Oct 8, 2024

Confirmed on current main as well. Weirdly enough, it does not seem to happen when I shadow some other stdlib modules which are also imported from _pyrepl/console.py

@tomasr8 tomasr8 added the 3.14 bugs and security fixes label Oct 8, 2024
@hroncok
Copy link
Contributor

hroncok commented Oct 8, 2024

Weirdly enough, it does not seem to happen when I shadow some other stdlib modules which are also imported from _pyrepl/console.py

Any chance this does not happen with abc, last, sys, os but happens with others? E.g. with dataclasses, I get:

$ python3.13
Python 3.13.0 (main, Oct  8 2024, 00:00:00) [GCC 13.3.1 20240913 (Red Hat 13.3.1-3)] on linux
Type "help", "copyright", "credits" or "license" for more information.
warning: can't use pyrepl: cannot import name 'dataclass' from 'dataclasses' (/home/.../exploit/dataclasses.py)
>>> 

I believe that some modules are loaded before $the current working directory is added to sys.path by the site module (?).

@ZeroIntensity
Copy link
Member

Hmm, I wouldn't say this is a major security issue. I don't think the REPL is a very common attack vector, so I'm hesitant to add the security label.

cc @pablogsal (I'm not sure if you get notified when topic-repl is added.)

@aleksa
Copy link
Author

aleksa commented Oct 9, 2024

This issue poses a significant security risk as it potentially allows malicious code to be executed without the user's knowledge or consent. The current functionality permits users to navigate the file tree and access the Python REPL, where arbitrary code can be run at the current privilege level.

As a user, I often utilize the Python REPL for quick calculations or other brief tasks. However, I would never assume that this action could damage the system, especially considering the risk depends on the current folder location. This misconception highlights the danger of the current implementation.

This vulnerability could be exploited for various malicious purposes, including:

  • Phishing attacks
  • Intentional system damage
  • Unauthorized data access or manipulation

The risk is particularly concerning because users may inadvertently run harmful code while performing routine tasks, unaware of the potential consequences.

Given the severity of potential exploits and the ease with which users might unknowingly expose themselves to risk, I recommend prioritizing this issue for immediate attention and resolution.

@ZeroIntensity ZeroIntensity added the type-security A security issue label Oct 9, 2024
pablogsal added a commit to pablogsal/cpython that referenced this issue Oct 9, 2024
pablogsal added a commit to pablogsal/cpython that referenced this issue Oct 9, 2024
pablogsal added a commit to pablogsal/cpython that referenced this issue Oct 9, 2024
pablogsal added a commit to pablogsal/cpython that referenced this issue Oct 9, 2024
@gpshead
Copy link
Member

gpshead commented Oct 9, 2024

Why is this considered new? I guess because the REPL now imports more stdlib modules than it did in the past before the prompt is shown?

Python has always put the current directory first in sys.path as '' which means that import code is going to load ./code.py instead of the stdlib code module unless you ran in python -I mode which disables this long standing default sys.path "feature" that would not be done when designing something new this decade instead of in the 1990s.

As for why people consider this a security problem of late: People with Python installed are increasingly being targeted by drive by download and or other file placement opportunistic attacks. Get something to save a stdlibmodulename.py in a browser Downloads directory - then anytime later for any reason when the user runs python while their current directory is Downloads or as python Downloads/new_thing.py.. bam, unintended arbitrary code execution that isn't obvious to many users when stdlibmodulename is imported.

It isn't a flaw in Python. It's merely a well known existing attack vector that has expanded a little in 3.13. It is a long standing feature relied upon by a lot of the world at the same time as being problematic in this type of scenario.

Mitigation wise to prevent 3.13 surprise, I think you're basically asking for python -I behavior until after the first repl prompt is shown. Which seems to be what PR #125212 aims to do.

@sethmlarson
Copy link
Contributor

Going to agree with @gpshead that this doesn't represent any additional risk of using PyREPL compared to the typical Python REPL or any Python application. Even if this specific issue is fixed ("PyREPL no longer loading ./code.py) then attackers can just as well use modules that were used before (./sys.py, ./os.py I presume).

The overall behavior of being able to shadow stdlib module names in local programs would be worth fixing from a security POV, but this specific behavior from PyREPL isn't any worse than that status-quo.

@vstinner
Copy link
Member

vstinner commented Oct 9, 2024

The -P command line option can be used to avoid this issue: https://docs.python.org/dev/using/cmdline.html#cmdoption-P

@hroncok
Copy link
Contributor

hroncok commented Oct 9, 2024

Why is this considered new?

Previously, I needed to open a REPL and run a command that imports something to trigger the problem. Now I open a REPL and it imports modules from the current directory on its own right away. That's new. Even if I am aware of the Python behavior and my intention in the REPL is to never import anything (e.g. I plan to use it as a calculator) or to immediately del sys.path[0] (as importing sys actually works even if sys.py exists in the current directory), the new REPL will import code.py (or other modules) from my directory.

pablogsal added a commit to pablogsal/cpython that referenced this issue Oct 9, 2024
@pablogsal
Copy link
Member

The reason this was not a problem before is some happy coincidence: site.py doesn't import anything that doesn't get imported by rlcompleter and that is not frozen after this line runs:

mod = PyImport_ImportModule("rlcompleter");

As that line runs too early, nothing gets pulled from the local dir because at that time . is not on the path.

@ambv
Copy link
Contributor

ambv commented Oct 9, 2024

Previously, I needed to open a REPL and run a command that imports something to trigger the problem. Now I open a REPL and it imports modules from the current directory on its own right away. That's new.

Not new but has been fixed in the past:
#92345

ambv added a commit that referenced this issue Oct 9, 2024
…pl (GH-125212)

Signed-off-by: Pablo Galindo <[email protected]>
Co-authored-by: Łukasz Langa <[email protected]>
Co-authored-by: Peter Bierma <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Oct 9, 2024
…g pyrepl (pythonGH-125212)

(cherry picked from commit c7d5d1d)

Co-authored-by: Pablo Galindo Salgado <[email protected]>
Signed-off-by: Pablo Galindo <[email protected]>
Co-authored-by: Łukasz Langa <[email protected]>
Co-authored-by: Peter Bierma <[email protected]>
@pablogsal
Copy link
Member

#125212 will do the trick

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.13 bugs and security fixes 3.14 bugs and security fixes topic-repl Related to the interactive shell type-bug An unexpected behavior, bug, or error type-security A security issue
Projects
None yet
Development

No branches or pull requests

10 participants