@@ -539,6 +539,23 @@ class Remote(LazyMixin, IterableObj):
539539 __slots__ = ("repo" , "name" , "_config_reader" )
540540 _id_attribute_ = "name"
541541
542+ unsafe_git_fetch_options = [
543+ # This option allows users to execute arbitrary commands.
544+ # https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---upload-packltupload-packgt
545+ "--upload-pack" ,
546+ ]
547+ unsafe_git_pull_options = [
548+ # This option allows users to execute arbitrary commands.
549+ # https://git-scm.com/docs/git-pull#Documentation/git-pull.txt---upload-packltupload-packgt
550+ "--upload-pack"
551+ ]
552+ unsafe_git_push_options = [
553+ # This option allows users to execute arbitrary commands.
554+ # https://git-scm.com/docs/git-push#Documentation/git-push.txt---execltgit-receive-packgt
555+ "--receive-pack" ,
556+ "--exec" ,
557+ ]
558+
542559 def __init__ (self , repo : "Repo" , name : str ) -> None :
543560 """Initialize a remote instance
544561
@@ -615,7 +632,9 @@ def iter_items(cls, repo: "Repo", *args: Any, **kwargs: Any) -> Iterator["Remote
615632 yield Remote (repo , section [lbound + 1 : rbound ])
616633 # END for each configuration section
617634
618- def set_url (self , new_url : str , old_url : Optional [str ] = None , ** kwargs : Any ) -> "Remote" :
635+ def set_url (
636+ self , new_url : str , old_url : Optional [str ] = None , allow_unsafe_protocols : bool = False , ** kwargs : Any
637+ ) -> "Remote" :
619638 """Configure URLs on current remote (cf command git remote set_url)
620639
621640 This command manages URLs on the remote.
@@ -624,15 +643,17 @@ def set_url(self, new_url: str, old_url: Optional[str] = None, **kwargs: Any) ->
624643 :param old_url: when set, replaces this URL with new_url for the remote
625644 :return: self
626645 """
646+ if not allow_unsafe_protocols :
647+ Git .check_unsafe_protocols (new_url )
627648 scmd = "set-url"
628649 kwargs ["insert_kwargs_after" ] = scmd
629650 if old_url :
630- self .repo .git .remote (scmd , self .name , new_url , old_url , ** kwargs )
651+ self .repo .git .remote (scmd , "--" , self .name , new_url , old_url , ** kwargs )
631652 else :
632- self .repo .git .remote (scmd , self .name , new_url , ** kwargs )
653+ self .repo .git .remote (scmd , "--" , self .name , new_url , ** kwargs )
633654 return self
634655
635- def add_url (self , url : str , ** kwargs : Any ) -> "Remote" :
656+ def add_url (self , url : str , allow_unsafe_protocols : bool = False , ** kwargs : Any ) -> "Remote" :
636657 """Adds a new url on current remote (special case of git remote set_url)
637658
638659 This command adds new URLs to a given remote, making it possible to have
@@ -641,7 +662,7 @@ def add_url(self, url: str, **kwargs: Any) -> "Remote":
641662 :param url: string being the URL to add as an extra remote URL
642663 :return: self
643664 """
644- return self .set_url (url , add = True )
665+ return self .set_url (url , add = True , allow_unsafe_protocols = allow_unsafe_protocols )
645666
646667 def delete_url (self , url : str , ** kwargs : Any ) -> "Remote" :
647668 """Deletes a new url on current remote (special case of git remote set_url)
@@ -733,7 +754,7 @@ def stale_refs(self) -> IterableList[Reference]:
733754 return out_refs
734755
735756 @classmethod
736- def create (cls , repo : "Repo" , name : str , url : str , ** kwargs : Any ) -> "Remote" :
757+ def create (cls , repo : "Repo" , name : str , url : str , allow_unsafe_protocols : bool = False , ** kwargs : Any ) -> "Remote" :
737758 """Create a new remote to the given repository
738759 :param repo: Repository instance that is to receive the new remote
739760 :param name: Desired name of the remote
@@ -743,7 +764,10 @@ def create(cls, repo: "Repo", name: str, url: str, **kwargs: Any) -> "Remote":
743764 :raise GitCommandError: in case an origin with that name already exists"""
744765 scmd = "add"
745766 kwargs ["insert_kwargs_after" ] = scmd
746- repo .git .remote (scmd , name , Git .polish_url (url ), ** kwargs )
767+ url = Git .polish_url (url )
768+ if not allow_unsafe_protocols :
769+ Git .check_unsafe_protocols (url )
770+ repo .git .remote (scmd , "--" , name , url , ** kwargs )
747771 return cls (repo , name )
748772
749773 # add is an alias
@@ -925,6 +949,8 @@ def fetch(
925949 progress : Union [RemoteProgress , None , "UpdateProgress" ] = None ,
926950 verbose : bool = True ,
927951 kill_after_timeout : Union [None , float ] = None ,
952+ allow_unsafe_protocols : bool = False ,
953+ allow_unsafe_options : bool = False ,
928954 ** kwargs : Any ,
929955 ) -> IterableList [FetchInfo ]:
930956 """Fetch the latest changes for this remote
@@ -967,6 +993,14 @@ def fetch(
967993 else :
968994 args = [refspec ]
969995
996+ if not allow_unsafe_protocols :
997+ for ref in args :
998+ if ref :
999+ Git .check_unsafe_protocols (ref )
1000+
1001+ if not allow_unsafe_options :
1002+ Git .check_unsafe_options (options = list (kwargs .keys ()), unsafe_options = self .unsafe_git_fetch_options )
1003+
9701004 proc = self .repo .git .fetch (
9711005 "--" , self , * args , as_process = True , with_stdout = False , universal_newlines = True , v = verbose , ** kwargs
9721006 )
@@ -980,6 +1014,8 @@ def pull(
9801014 refspec : Union [str , List [str ], None ] = None ,
9811015 progress : Union [RemoteProgress , "UpdateProgress" , None ] = None ,
9821016 kill_after_timeout : Union [None , float ] = None ,
1017+ allow_unsafe_protocols : bool = False ,
1018+ allow_unsafe_options : bool = False ,
9831019 ** kwargs : Any ,
9841020 ) -> IterableList [FetchInfo ]:
9851021 """Pull changes from the given branch, being the same as a fetch followed
@@ -994,6 +1030,15 @@ def pull(
9941030 # No argument refspec, then ensure the repo's config has a fetch refspec.
9951031 self ._assert_refspec ()
9961032 kwargs = add_progress (kwargs , self .repo .git , progress )
1033+
1034+ refspec = Git ._unpack_args (refspec or [])
1035+ if not allow_unsafe_protocols :
1036+ for ref in refspec :
1037+ Git .check_unsafe_protocols (ref )
1038+
1039+ if not allow_unsafe_options :
1040+ Git .check_unsafe_options (options = list (kwargs .keys ()), unsafe_options = self .unsafe_git_pull_options )
1041+
9971042 proc = self .repo .git .pull (
9981043 "--" , self , refspec , with_stdout = False , as_process = True , universal_newlines = True , v = True , ** kwargs
9991044 )
@@ -1007,6 +1052,8 @@ def push(
10071052 refspec : Union [str , List [str ], None ] = None ,
10081053 progress : Union [RemoteProgress , "UpdateProgress" , Callable [..., RemoteProgress ], None ] = None ,
10091054 kill_after_timeout : Union [None , float ] = None ,
1055+ allow_unsafe_protocols : bool = False ,
1056+ allow_unsafe_options : bool = False ,
10101057 ** kwargs : Any ,
10111058 ) -> PushInfoList :
10121059 """Push changes from source branch in refspec to target branch in refspec.
@@ -1037,6 +1084,15 @@ def push(
10371084 be 0.
10381085 Call ``.raise_if_error()`` on the returned object to raise on any failure."""
10391086 kwargs = add_progress (kwargs , self .repo .git , progress )
1087+
1088+ refspec = Git ._unpack_args (refspec or [])
1089+ if not allow_unsafe_protocols :
1090+ for ref in refspec :
1091+ Git .check_unsafe_protocols (ref )
1092+
1093+ if not allow_unsafe_options :
1094+ Git .check_unsafe_options (options = list (kwargs .keys ()), unsafe_options = self .unsafe_git_push_options )
1095+
10401096 proc = self .repo .git .push (
10411097 "--" ,
10421098 self ,
0 commit comments