Skip to content

Commit ea52206

Browse files
committed
Forbid unsafe protocol URLs in Repo.clone_from()
Since the URL is passed directly to git clone, and the remote-ext helper will happily execute shell commands, so by default disallow URLs that contain a "::" unless a new unsafe_protocols kwarg is passed. (CVE-2022-24439) Fixes #1515
1 parent 17ff263 commit ea52206

File tree

2 files changed

+24
-0
lines changed

2 files changed

+24
-0
lines changed

git/repo/base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,7 @@ def clone_from(
12531253
progress: Optional[Callable] = None,
12541254
env: Optional[Mapping[str, str]] = None,
12551255
multi_options: Optional[List[str]] = None,
1256+
unsafe_protocols: bool = False,
12561257
**kwargs: Any,
12571258
) -> "Repo":
12581259
"""Create a clone from the given URL
@@ -1268,10 +1269,13 @@ def clone_from(
12681269
as its value.
12691270
:param multi_options: See ``clone`` method
12701271
:param kwargs: see the ``clone`` method
1272+
:param unsafe_protocols: Allow unsafe protocols to be used, like ext::
12711273
:return: Repo instance pointing to the cloned directory"""
12721274
git = cls.GitCommandWrapperType(os.getcwd())
12731275
if env is not None:
12741276
git.update_environment(**env)
1277+
if not unsafe_protocols and "::" in url:
1278+
raise ValueError(f"{url} requires unsafe_protocols flag")
12751279
return cls._clone(git, url, to_path, GitCmdObjectDB, progress, multi_options, **kwargs)
12761280

12771281
def archive(

test/test_repo.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import pickle
1414
import sys
1515
import tempfile
16+
import uuid
1617
from unittest import mock, skipIf, SkipTest
1718

1819
import pytest
@@ -263,6 +264,25 @@ def test_leaking_password_in_clone_logs(self, rw_dir):
263264
to_path=rw_dir,
264265
)
265266

267+
def test_clone_from_forbids_helper_urls_by_default(self):
268+
with self.assertRaises(ValueError):
269+
Repo.clone_from("ext::sh -c touch% /tmp/foo", "tmp")
270+
271+
@with_rw_repo("HEAD")
272+
def test_clone_from_allow_unsafe(self, repo):
273+
bad_filename = pathlib.Path(f'{tempfile.gettempdir()}/{uuid.uuid4()}')
274+
bad_url = f'ext::sh -c touch% {bad_filename}'
275+
try:
276+
repo.clone_from(
277+
bad_url, 'tmp',
278+
multi_options=["-c protocol.ext.allow=always"],
279+
unsafe_protocols=True
280+
)
281+
except GitCommandError:
282+
pass
283+
self.assertTrue(bad_filename.is_file())
284+
bad_filename.unlink()
285+
266286
@with_rw_repo("HEAD")
267287
def test_max_chunk_size(self, repo):
268288
class TestOutputStream(TestBase):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy