| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent c99207e commit 9e8c85e
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -646,7 +646,8 @@ class Git(metaclass=_GitMeta): | |||
| 646 | 646 | ) | |
| 647 | 647 | ||
| 648 | 648 | # Match Git's leading transport selector, including an empty helper name. | |
| 649 | - re_unsafe_protocol = re.compile(r"([A-Za-z0-9][A-Za-z0-9+.-]*|)::") | ||
| 649 | + # Git also selects the command-executing ext helper for an ext:// URL. | ||
| 650 | + re_unsafe_protocol = re.compile(r"([A-Za-z0-9][A-Za-z0-9+.-]*|)::|ext://") | ||
| 650 | 651 | ||
| 651 | 652 | unsafe_git_ls_remote_options = [ | |
| 652 | 653 | # This option allows arbitrary command execution in git-ls-remote. | |
@@ -946,7 +947,8 @@ def check_unsafe_protocols(cls, url: str) -> None: | |||
| 946 | 947 | ||
| 947 | 948 | Apart from the usual protocols (http, git, ssh), Git allows "remote helpers" | |
| 948 | 949 | that have the form ``<transport>::<address>``. One of these helpers (``ext::``) | |
| 949 | - can be used to invoke any arbitrary command. | ||
| 950 | + can be used to invoke any arbitrary command. Git also selects that helper | ||
| 951 | + for ``ext://`` URLs and interprets the URL as a command path. | ||
| 950 | 952 | ||
| 951 | 953 | See: | |
| 952 | 954 | ||
@@ -955,9 +957,9 @@ def check_unsafe_protocols(cls, url: str) -> None: | |||
| 955 | 957 | """ | |
| 956 | 958 | match = cls.re_unsafe_protocol.match(url) | |
| 957 | 959 | if match: | |
| 958 | - protocol = match.group(1) | ||
| 960 | + protocol = match.group(0) | ||
| 959 | 961 | raise UnsafeProtocolError( | |
| 960 | - f"The `{protocol}::` protocol looks suspicious, use `allow_unsafe_protocols=True` to allow it." | ||
| 962 | + f"The `{protocol}` protocol looks suspicious, use `allow_unsafe_protocols=True` to allow it." | ||
| 961 | 963 | ) | |
| 962 | 964 | ||
| 963 | 965 | @classmethod | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -36,6 +36,29 @@ def test_ls_remote_rejects_unsafe_protocols(args, kwargs, allow_unsafe_options): | |||
| 36 | 36 | run.assert_not_called() | |
| 37 | 37 | ||
| 38 | 38 | ||
| 39 | + @pytest.mark.parametrize("through_repo", (False, True)) | ||
| 40 | + @pytest.mark.parametrize("remote", ("ext::helper", "ext://helper")) | ||
| 41 | + def test_ls_remote_protocol_guard_at_both_entry_points(tmp_path, through_repo, remote): | ||
| 42 | + with Repo.init(tmp_path) as repo: | ||
| 43 | + command = repo.git if through_repo else Git() | ||
| 44 | + with mock.patch.object(Git, "execute", return_value="refs") as execute: | ||
| 45 | + for allow_unsafe_options in (False, True): | ||
| 46 | + with pytest.raises(UnsafeProtocolError): | ||
| 47 | + command.ls_remote(remote, allow_unsafe_options=allow_unsafe_options) | ||
| 48 | + execute.assert_not_called() | ||
| 49 | + | ||
| 50 | + url = "ssh://git@[2001:db8::1]/repo.git" | ||
| 51 | + assert command.ls_remote(url) == "refs" | ||
| 52 | + execute.assert_called_once_with([Git.GIT_PYTHON_GIT_EXECUTABLE, "ls-remote", url]) | ||
| 53 | + execute.reset_mock() | ||
| 54 | + | ||
| 55 | + with pytest.raises(UnsafeOptionError): | ||
| 56 | + command.ls_remote(remote, upload_pack="helper", allow_unsafe_protocols=True) | ||
| 57 | + execute.assert_not_called() | ||
| 58 | + assert command.ls_remote(remote, allow_unsafe_protocols=True) == "refs" | ||
| 59 | + execute.assert_called_once_with([Git.GIT_PYTHON_GIT_EXECUTABLE, "ls-remote", remote]) | ||
| 60 | + | ||
| 61 | + | ||
| 39 | 62 | @pytest.mark.parametrize( | |
| 40 | 63 | "args, kwargs", | |
| 41 | 64 | [ | |
| Back | FazBrowse Home | New Git URL |
0 commit comments