Skip to content

Commit

Permalink
Quote URLs in Repo.clone_from()
Browse files Browse the repository at this point in the history
Since the URL is passed directly to git clone, and the remote-ext helper
will happily execute shell commands, so by default qoute URLs unless a
(undocumented, on purpose) kwarg is passed. (CVE-2022-24439)

Fixes gitpython-developers#1515
  • Loading branch information
s-t-e-v-e-n-k committed Dec 13, 2022
1 parent 17ff263 commit 03753c0
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 0 deletions.
3 changes: 3 additions & 0 deletions git/repo/base.py
Expand Up @@ -8,6 +8,7 @@
import os
import re
import shlex
import urllib.parse
import warnings
from gitdb.db.loose import LooseObjectDB

Expand Down Expand Up @@ -1272,6 +1273,8 @@ def clone_from(
git = cls.GitCommandWrapperType(os.getcwd())
if env is not None:
git.update_environment(**env)
if 'unsafe_protocols' not in kwargs:
url = urllib.parse.quote(url)
return cls._clone(git, url, to_path, GitCmdObjectDB, progress, multi_options, **kwargs)

def archive(
Expand Down
13 changes: 13 additions & 0 deletions test/test_repo.py
Expand Up @@ -13,6 +13,7 @@
import pickle
import sys
import tempfile
import uuid
from unittest import mock, skipIf, SkipTest

import pytest
Expand Down Expand Up @@ -263,6 +264,18 @@ def test_leaking_password_in_clone_logs(self, rw_dir):
to_path=rw_dir,
)

@with_rw_repo("HEAD")
def test_clone_from_quotes_urls_by_default(self, repo):
bad_filename = f'{tempfile.gettempdir()}/{uuid.uuid4()}'
bad_url = f'ext::sh -c touch% {bad_filename}'
try:
repo.clone_from(
bad_url, 'tmp', multi_options=["-c protocol.ext.allow=always"]
)
except GitCommandError:
pass
self.assertFalse(pathlib.Path(bad_filename).is_file())

@with_rw_repo("HEAD")
def test_max_chunk_size(self, repo):
class TestOutputStream(TestBase):
Expand Down

0 comments on commit 03753c0

Please sign in to comment.