Skip to content

Commit 0119404

Browse files
codexByron
authored andcommitted
Reject abbreviated unsafe git options
Git's parse-options machinery accepts an unambiguous prefix of a long option. In the reference Git checkout, parse-options.c records abbreviated matches in parse_long_opt() and dispatches the abbreviated option when it is not ambiguous. GitPython normalized unsafe option names before comparing them to the deny-list, but only exact canonical names were rejected. That allowed forms such as --upl=... to bypass the --upload-pack guard while still being interpreted by Git as the unsafe option. Make the shared unsafe-option check reject non-empty canonical candidates that are prefixes of blocked canonical option names, while preserving exact-match behavior. Add coverage for the shared helper and for clone, fetch, pull, push, and ls-remote abbreviation forms. Validation: - .venv/bin/python -m compileall -q git/cmd.py test/test_git.py test/test_clone.py test/test_remote.py - git diff --check - Focused pytest/unittest execution could not run because the environment is missing pytest, ddt, and gitdb, and PyPI access failed while installing test-requirements.txt.
1 parent 6d45f17 commit 0119404

3 files changed

Lines changed: 16 additions & 1 deletion

File tree

test/test_clone.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,13 @@ def test_clone_unsafe_options(self, rw_repo):
117117
tmp_file = tmp_dir / "pwn"
118118
unsafe_options = [
119119
f"--upload-pack='touch {tmp_file}'",
120+
f"--upl='touch {tmp_file}'",
120121
f"-u 'touch {tmp_file}'",
121122
f"-utouch {tmp_file}; false",
122123
f"-futouch${{IFS}}{tmp_file}; false",
123124
f"-qutouch${{IFS}}{tmp_file}; false",
124125
"--config=protocol.ext.allow=always",
126+
"--conf=protocol.ext.allow=always",
125127
"-c protocol.ext.allow=always",
126128
"-cprotocol.ext.allow=always",
127129
"-vcprotocol.ext.allow=always",
@@ -134,8 +136,10 @@ def test_clone_unsafe_options(self, rw_repo):
134136
unsafe_options = [
135137
{"upload-pack": f"touch {tmp_file}"},
136138
{"upload_pack": f"touch {tmp_file}"},
139+
{"upl": f"touch {tmp_file}"},
137140
{"u": f"touch {tmp_file}"},
138141
{"config": "protocol.ext.allow=always"},
142+
{"conf": "protocol.ext.allow=always"},
139143
{"c": "protocol.ext.allow=always"},
140144
]
141145
for unsafe_option in unsafe_options:

test/test_git.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ def test_check_unsafe_options_normalizes_kwargs(self):
164164
(["c"], ["-c"]),
165165
(["--upload-pack=/tmp/helper"], ["--upload-pack"]),
166166
(["--config core.filemode=false"], ["--config"]),
167+
(["--upl=/tmp/helper"], ["--upload-pack"]),
168+
(["conf"], ["--config"]),
169+
(["--out=/tmp/output"], ["--output"]),
167170
]
168171

169172
for options, unsafe_options in cases:

test/test_remote.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1022,14 +1022,22 @@ def test_ls_remote_unsafe_options(self, rw_repo):
10221022
with tempfile.TemporaryDirectory() as tdir:
10231023
tmp_dir = Path(tdir)
10241024
tmp_file = tmp_dir / "pwn"
1025-
unsafe_options = [{"upload-pack": f"touch {tmp_file}"}, {"upload_pack": f"touch {tmp_file}"}]
1025+
unsafe_options = [
1026+
{"upload-pack": f"touch {tmp_file}"},
1027+
{"upload_pack": f"touch {tmp_file}"},
1028+
{"upl": f"touch {tmp_file}"},
1029+
]
10261030
for unsafe_option in unsafe_options:
10271031
with self.assertRaises(UnsafeOptionError):
10281032
rw_repo.git.ls_remote(".", **unsafe_option)
10291033
with self.assertRaises(UnsafeOptionError):
10301034
rw_repo.git.ls_remote([f"--upload-pack={tmp_file}"], ".")
1035+
with self.assertRaises(UnsafeOptionError):
1036+
rw_repo.git.ls_remote([f"--upl={tmp_file}"], ".")
10311037
with self.assertRaises(UnsafeOptionError):
10321038
rw_repo.git.ls_remote(f"--upload-pack={tmp_file}", ".")
1039+
with self.assertRaises(UnsafeOptionError):
1040+
rw_repo.git.ls_remote(f"--upl={tmp_file}", ".")
10331041
with self.assertRaises(UnsafeOptionError):
10341042
rw_repo.git.ls_remote("--upload-pack", "touch", ".")
10351043

0 commit comments

Comments
 (0)