summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Thiel <sebastian.thiel@icloud.com>2022-12-22 17:08:42 +0100
committerSebastian Thiel <sebastian.thiel@icloud.com>2022-12-22 17:08:42 +0100
commit787359d80d80225095567340aa5e7ec01847fa9a (patch)
tree41947c5be7875e746b6e1452add2b92283e926b4
parent17ff2630af26b37f82ac1158ee3495c4390da699 (diff)
parent2aae532a3993a100d5074cde70abe548cfc45861 (diff)
downloadgitpython-787359d80d80225095567340aa5e7ec01847fa9a.tar.gz
Merge branch 'fix-cmd-injection'
-rw-r--r--.github/workflows/pythonpackage.yml2
-rw-r--r--doc/source/changes.rst12
-rw-r--r--git/remote.py5
-rw-r--r--git/repo/base.py3
-rw-r--r--test/test_repo.py26
5 files changed, 44 insertions, 4 deletions
diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml
index 5c698bae..5373dace 100644
--- a/.github/workflows/pythonpackage.yml
+++ b/.github/workflows/pythonpackage.yml
@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- 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"]
+ python-version: [3.7, 3.8, 3.9, "3.10", "3.11"]
steps:
- uses: actions/checkout@v3
diff --git a/doc/source/changes.rst b/doc/source/changes.rst
index d36194c8..a784a096 100644
--- a/doc/source/changes.rst
+++ b/doc/source/changes.rst
@@ -2,6 +2,18 @@
Changelog
=========
+3.1.30
+======
+
+- Make injections of command-invocations harder or impossible for clone and others.
+ See https://github.com/gitpython-developers/GitPython/pull/1518 for details.
+ Note that this might constitute a breaking change for some users, and if so please
+ let us know and we add an opt-out to this.
+
+See the following for all changes.
+https://github.com/gitpython-developers/gitpython/milestone/60?closed=1
+
+
3.1.29
======
diff --git a/git/remote.py b/git/remote.py
index 7b44020c..483d536a 100644
--- a/git/remote.py
+++ b/git/remote.py
@@ -964,7 +964,7 @@ class Remote(LazyMixin, IterableObj):
args = [refspec]
proc = self.repo.git.fetch(
- self, *args, as_process=True, with_stdout=False, universal_newlines=True, v=verbose, **kwargs
+ "--", self, *args, as_process=True, with_stdout=False, universal_newlines=True, v=verbose, **kwargs
)
res = self._get_fetch_info_from_stderr(proc, progress, kill_after_timeout=kill_after_timeout)
if hasattr(self.repo.odb, "update_cache"):
@@ -991,7 +991,7 @@ class Remote(LazyMixin, IterableObj):
self._assert_refspec()
kwargs = add_progress(kwargs, self.repo.git, progress)
proc = self.repo.git.pull(
- self, refspec, with_stdout=False, as_process=True, universal_newlines=True, v=True, **kwargs
+ "--", self, refspec, with_stdout=False, as_process=True, universal_newlines=True, v=True, **kwargs
)
res = self._get_fetch_info_from_stderr(proc, progress, kill_after_timeout=kill_after_timeout)
if hasattr(self.repo.odb, "update_cache"):
@@ -1034,6 +1034,7 @@ class Remote(LazyMixin, IterableObj):
be 0."""
kwargs = add_progress(kwargs, self.repo.git, progress)
proc = self.repo.git.push(
+ "--",
self,
refspec,
porcelain=True,
diff --git a/git/repo/base.py b/git/repo/base.py
index c49c6118..49a3d5a1 100644
--- a/git/repo/base.py
+++ b/git/repo/base.py
@@ -1169,6 +1169,7 @@ class Repo(object):
multi = shlex.split(" ".join(multi_options))
proc = git.clone(
multi,
+ "--",
Git.polish_url(str(url)),
clone_path,
with_extended_output=True,
@@ -1305,7 +1306,7 @@ class Repo(object):
if not isinstance(path, (tuple, list)):
path = [path]
# end assure paths is list
- self.git.archive(treeish, *path, **kwargs)
+ self.git.archive("--", treeish, *path, **kwargs)
return self
def has_separate_working_tree(self) -> bool:
diff --git a/test/test_repo.py b/test/test_repo.py
index 703dbb43..6382db7e 100644
--- a/test/test_repo.py
+++ b/test/test_repo.py
@@ -1180,3 +1180,29 @@ class TestRepo(TestBase):
r.git.add(Git.polish_url(fp))
r.git.commit(message="init")
self.assertEqual(r.git.show("HEAD:hello.txt", strip_newline_in_stdout=False), "hello\n")
+
+ @with_rw_repo("HEAD")
+ def test_clone_command_injection(self, rw_repo):
+ tmp_dir = pathlib.Path(tempfile.mkdtemp())
+ unexpected_file = tmp_dir / "pwn"
+ assert not unexpected_file.exists()
+
+ payload = f"--upload-pack=touch {unexpected_file}"
+ rw_repo.clone(payload)
+
+ assert not unexpected_file.exists()
+ # A repo was cloned with the payload as name
+ assert pathlib.Path(payload).exists()
+
+ @with_rw_repo("HEAD")
+ def test_clone_from_command_injection(self, rw_repo):
+ tmp_dir = pathlib.Path(tempfile.mkdtemp())
+ temp_repo = Repo.init(tmp_dir / "repo")
+ unexpected_file = tmp_dir / "pwn"
+
+ assert not unexpected_file.exists()
+ payload = f"--upload-pack=touch {unexpected_file}"
+ with self.assertRaises(GitCommandError):
+ rw_repo.clone_from(payload, temp_repo.common_dir)
+
+ assert not unexpected_file.exists()