diff --git a/poetry/core/vcs/git.py b/poetry/core/vcs/git.py index e1b7a8711..dda509236 100644 --- a/poetry/core/vcs/git.py +++ b/poetry/core/vcs/git.py @@ -92,6 +92,11 @@ ] +class GitError(RuntimeError): + + pass + + class ParsedUrl: def __init__( self, @@ -209,7 +214,9 @@ def config(self): # type: () -> GitConfig return self._config def clone(self, repository, dest): # type: (str, Path) -> str - return self.run("clone", "--recurse-submodules", repository, str(dest)) + self._check_parameter(repository) + + return self.run("clone", "--recurse-submodules", "--", repository, str(dest)) def checkout(self, rev, folder=None): # type: (str, Optional[Path]) -> str args = [] @@ -224,6 +231,8 @@ def checkout(self, rev, folder=None): # type: (str, Optional[Path]) -> str folder.as_posix(), ] + self._check_parameter(rev) + args += ["checkout", rev] return self.run(*args) @@ -241,6 +250,8 @@ def rev_parse(self, rev, folder=None): # type: (str, Optional[Path]) -> str folder.as_posix(), ] + self._check_parameter(rev) + # We need "^0" (an alternative to "^{commit}") to ensure that the # commit SHA of the commit the tag points to is returned, even in # the case of annotated tags. @@ -301,3 +312,10 @@ def run(self, *args, **kwargs): # type: (*Any, **Any) -> str return decode( subprocess.check_output(["git"] + list(args), stderr=subprocess.STDOUT) ).strip() + + def _check_parameter(self, parameter): # type: (str) -> None + """ + Checks a git parameter to avoid unwanted code execution. + """ + if parameter.strip().startswith("-"): + raise GitError("Invalid Git parameter: {}".format(parameter)) diff --git a/tests/vcs/test_vcs.py b/tests/vcs/test_vcs.py index c2f888fbd..1a5e39624 100644 --- a/tests/vcs/test_vcs.py +++ b/tests/vcs/test_vcs.py @@ -1,6 +1,8 @@ import pytest +from poetry.core.utils._compat import Path from poetry.core.vcs.git import Git +from poetry.core.vcs.git import GitError from poetry.core.vcs.git import GitUrl from poetry.core.vcs.git import ParsedUrl @@ -259,3 +261,18 @@ def test_parse_url_should_fail(): with pytest.raises(ValueError): ParsedUrl.parse(url) + + +def test_git_clone_raises_error_on_invalid_repository(): + with pytest.raises(GitError): + Git().clone("-u./payload", Path("foo")) + + +def test_git_checkout_raises_error_on_invalid_repository(): + with pytest.raises(GitError): + Git().checkout("-u./payload") + + +def test_git_rev_parse_raises_error_on_invalid_repository(): + with pytest.raises(GitError): + Git().rev_parse("-u./payload")