@@ -189,6 +189,7 @@ func (r *Repository) Fetch(opts ...FetchOptions) error {
189189 if opt .Prune {
190190 cmd .AddArgs ("--prune" )
191191 }
192+ cmd .AddArgs ("--end-of-options" )
192193
193194 _ , err := cmd .RunInDirWithTimeout (opt .Timeout , r .path )
194195 return err
@@ -229,6 +230,7 @@ func (r *Repository) Pull(opts ...PullOptions) error {
229230 if opt .All {
230231 cmd .AddArgs ("--all" )
231232 }
233+ cmd .AddArgs ("--end-of-options" )
232234 if ! opt .All && opt .Remote != "" {
233235 cmd .AddArgs (opt .Remote )
234236 if opt .Branch != "" {
@@ -300,11 +302,9 @@ func Checkout(repoPath, branch string, opts ...CheckoutOptions) error {
300302
301303 cmd := NewCommand ("checkout" ).AddOptions (opt .CommandOptions )
302304 if opt .BaseBranch != "" {
303- cmd .AddArgs ("-b" )
304- }
305- cmd .AddArgs (branch )
306- if opt .BaseBranch != "" {
307- cmd .AddArgs (opt .BaseBranch )
305+ cmd .AddArgs ("-b" , branch , "--end-of-options" , opt .BaseBranch )
306+ } else {
307+ cmd .AddArgs ("--end-of-options" , branch )
308308 }
309309
310310 _ , err := cmd .RunInDirWithTimeout (opt .Timeout , repoPath )
@@ -348,7 +348,7 @@ func Reset(repoPath, rev string, opts ...ResetOptions) error {
348348 cmd .AddArgs ("--hard" )
349349 }
350350
351- _ , err := cmd .AddOptions (opt .CommandOptions ).AddArgs (rev ).RunInDir (repoPath )
351+ _ , err := cmd .AddOptions (opt .CommandOptions ).AddArgs ("--end-of-options" , rev ).RunInDir (repoPath )
352352 return err
353353}
354354
@@ -476,7 +476,8 @@ func CreateCommit(repoPath string, committer *Signature, message string, opts ..
476476 }
477477 cmd = cmd .AddArgs (fmt .Sprintf ("--author='%s <%s>'" , opt .Author .Name , opt .Author .Email )).
478478 AddArgs ("-m" , message ).
479- AddOptions (opt .CommandOptions )
479+ AddOptions (opt .CommandOptions ).
480+ AddArgs ("--end-of-options" )
480481
481482 _ , err := cmd .RunInDirWithTimeout (opt .Timeout , repoPath )
482483 // No stderr but exit status 1 means nothing to commit.
@@ -593,6 +594,15 @@ func (r *Repository) RevParse(rev string, opts ...RevParseOptions) (string, erro
593594 opt = opts [0 ]
594595 }
595596
597+ // A revision that starts with a dash is never a valid object and would
598+ // instead be interpreted by "git rev-parse" as a command-line option,
599+ // allowing argument injection. The "--end-of-options" separator does not
600+ // help here because "git rev-parse" does not honor it for revisions, so
601+ // reject such input outright.
602+ if strings .HasPrefix (rev , "-" ) {
603+ return "" , ErrRevisionNotExist
604+ }
605+
596606 commitID , err := NewCommand ("rev-parse" ).
597607 AddOptions (opt .CommandOptions ).
598608 AddArgs (rev ).
@@ -640,6 +650,7 @@ func CountObjects(repoPath string, opts ...CountObjectsOptions) (*CountObject, e
640650
641651 stdout , err := NewCommand ("count-objects" , "-v" ).
642652 AddOptions (opt .CommandOptions ).
653+ AddArgs ("--end-of-options" ).
643654 RunInDirWithTimeout (opt .Timeout , repoPath )
644655 if err != nil {
645656 return nil , err
@@ -706,7 +717,7 @@ func Fsck(repoPath string, opts ...FsckOptions) error {
706717 opt = opts [0 ]
707718 }
708719
709- cmd := NewCommand ("fsck" ).AddOptions (opt .CommandOptions )
720+ cmd := NewCommand ("fsck" ).AddOptions (opt .CommandOptions ). AddArgs ( "--end-of-options" )
710721 _ , err := cmd .RunInDirWithTimeout (opt .Timeout , repoPath )
711722 return err
712723}
0 commit comments