Skip to content

Commit 787359d

Browse files
committed
Merge branch 'fix-cmd-injection'
2 parents 17ff263 + 2aae532 commit 787359d

File tree

5 files changed

+44
-4
lines changed

5 files changed

+44
-4
lines changed

Diff for: .github/workflows/pythonpackage.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
runs-on: ubuntu-latest
1919
strategy:
2020
matrix:
21-
python-version: [3.7, 3.7.5, 3.7.12, 3.8, 3.8.0, 3.8.11, 3.8, 3.9, 3.9.0, 3.9.7, "3.10"]
21+
python-version: [3.7, 3.8, 3.9, "3.10", "3.11"]
2222

2323
steps:
2424
- uses: actions/checkout@v3

Diff for: doc/source/changes.rst

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22
Changelog
33
=========
44

5+
3.1.30
6+
======
7+
8+
- Make injections of command-invocations harder or impossible for clone and others.
9+
See https://github.com/gitpython-developers/GitPython/pull/1518 for details.
10+
Note that this might constitute a breaking change for some users, and if so please
11+
let us know and we add an opt-out to this.
12+
13+
See the following for all changes.
14+
https://github.com/gitpython-developers/gitpython/milestone/60?closed=1
15+
16+
517
3.1.29
618
======
719

Diff for: git/remote.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,7 @@ def fetch(
964964
args = [refspec]
965965

966966
proc = self.repo.git.fetch(
967-
self, *args, as_process=True, with_stdout=False, universal_newlines=True, v=verbose, **kwargs
967+
"--", self, *args, as_process=True, with_stdout=False, universal_newlines=True, v=verbose, **kwargs
968968
)
969969
res = self._get_fetch_info_from_stderr(proc, progress, kill_after_timeout=kill_after_timeout)
970970
if hasattr(self.repo.odb, "update_cache"):
@@ -991,7 +991,7 @@ def pull(
991991
self._assert_refspec()
992992
kwargs = add_progress(kwargs, self.repo.git, progress)
993993
proc = self.repo.git.pull(
994-
self, refspec, with_stdout=False, as_process=True, universal_newlines=True, v=True, **kwargs
994+
"--", self, refspec, with_stdout=False, as_process=True, universal_newlines=True, v=True, **kwargs
995995
)
996996
res = self._get_fetch_info_from_stderr(proc, progress, kill_after_timeout=kill_after_timeout)
997997
if hasattr(self.repo.odb, "update_cache"):
@@ -1034,6 +1034,7 @@ def push(
10341034
be 0."""
10351035
kwargs = add_progress(kwargs, self.repo.git, progress)
10361036
proc = self.repo.git.push(
1037+
"--",
10371038
self,
10381039
refspec,
10391040
porcelain=True,

Diff for: git/repo/base.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,7 @@ def _clone(
11691169
multi = shlex.split(" ".join(multi_options))
11701170
proc = git.clone(
11711171
multi,
1172+
"--",
11721173
Git.polish_url(str(url)),
11731174
clone_path,
11741175
with_extended_output=True,
@@ -1305,7 +1306,7 @@ def archive(
13051306
if not isinstance(path, (tuple, list)):
13061307
path = [path]
13071308
# end assure paths is list
1308-
self.git.archive(treeish, *path, **kwargs)
1309+
self.git.archive("--", treeish, *path, **kwargs)
13091310
return self
13101311

13111312
def has_separate_working_tree(self) -> bool:

Diff for: test/test_repo.py

+26
Original file line numberDiff line numberDiff line change
@@ -1180,3 +1180,29 @@ def test_do_not_strip_newline_in_stdout(self, rw_dir):
11801180
r.git.add(Git.polish_url(fp))
11811181
r.git.commit(message="init")
11821182
self.assertEqual(r.git.show("HEAD:hello.txt", strip_newline_in_stdout=False), "hello\n")
1183+
1184+
@with_rw_repo("HEAD")
1185+
def test_clone_command_injection(self, rw_repo):
1186+
tmp_dir = pathlib.Path(tempfile.mkdtemp())
1187+
unexpected_file = tmp_dir / "pwn"
1188+
assert not unexpected_file.exists()
1189+
1190+
payload = f"--upload-pack=touch {unexpected_file}"
1191+
rw_repo.clone(payload)
1192+
1193+
assert not unexpected_file.exists()
1194+
# A repo was cloned with the payload as name
1195+
assert pathlib.Path(payload).exists()
1196+
1197+
@with_rw_repo("HEAD")
1198+
def test_clone_from_command_injection(self, rw_repo):
1199+
tmp_dir = pathlib.Path(tempfile.mkdtemp())
1200+
temp_repo = Repo.init(tmp_dir / "repo")
1201+
unexpected_file = tmp_dir / "pwn"
1202+
1203+
assert not unexpected_file.exists()
1204+
payload = f"--upload-pack=touch {unexpected_file}"
1205+
with self.assertRaises(GitCommandError):
1206+
rw_repo.clone_from(payload, temp_repo.common_dir)
1207+
1208+
assert not unexpected_file.exists()

0 commit comments

Comments
 (0)