From a225320c82c189a91b0dc6fa588766627547e182 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 03:05:37 +0000 Subject: [PATCH 1/3] Initial plan From db5c06d8e0022c04c894e9426880062baaa47a61 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 03:15:46 +0000 Subject: [PATCH 2/3] Guard git command args against flag injection (Sighthound findings) Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/experiments_command.go | 7 +++++++ pkg/cli/git.go | 13 +++++++++++++ pkg/cli/git_test.go | 22 ++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/pkg/cli/experiments_command.go b/pkg/cli/experiments_command.go index 04011aeabcf..c03299d92c6 100644 --- a/pkg/cli/experiments_command.go +++ b/pkg/cli/experiments_command.go @@ -334,6 +334,10 @@ func loadLocalMetricEvalResults(workflowID string) map[string]MetricEvalResults } ref = branchName } + if !isSafeGitRevisionArg(ref) { + experimentsLog.Printf("Rejecting unsafe git ref: %q", ref) + return nil + } cmd := exec.Command("git", "show", ref+":"+constants.EvalsResultFilename) out, err := cmd.Output() if err != nil { @@ -907,6 +911,9 @@ func extractExperimentName(ref string) string { // gitRefExists reports whether a git ref exists locally. func gitRefExists(ref string) bool { + if !isSafeGitRevisionArg(ref) { + return false + } cmd := exec.Command("git", "rev-parse", "--verify", ref) return cmd.Run() == nil } diff --git a/pkg/cli/git.go b/pkg/cli/git.go index b2b7d115983..8faebf1332e 100644 --- a/pkg/cli/git.go +++ b/pkg/cli/git.go @@ -19,6 +19,14 @@ import ( var gitLog = logger.New("cli:git") +// isSafeGitRevisionArg reports whether ref is safe to pass as a git revision +// argument (e.g. to "git log ..HEAD" or "git show :"). +// It rejects empty values and values starting with "-", which could +// otherwise be misinterpreted as command-line options (flag injection). +func isSafeGitRevisionArg(ref string) bool { + return ref != "" && !strings.HasPrefix(ref, "-") +} + func isGitRepo() bool { _, err := gitutil.FindGitRoot() return err == nil @@ -689,6 +697,11 @@ func checkWorkflowFileStatus(workflowPath string) (*WorkflowFileStatus, error) { upstream := strings.TrimSpace(string(output)) gitLog.Printf("Upstream branch: %s", upstream) + if !isSafeGitRevisionArg(upstream) { + gitLog.Printf("Rejecting unsafe upstream ref: %q", upstream) + return status, nil // Ignore unexpected/unsafe upstream ref, return current status + } + // Check if there are commits in the current branch that affect this file and aren't in upstream cmd = exec.Command("git", "-C", gitRoot, "log", upstream+"..HEAD", "--oneline", "--", relPath) output, err = cmd.Output() diff --git a/pkg/cli/git_test.go b/pkg/cli/git_test.go index b5a74562541..96dea9f73ed 100644 --- a/pkg/cli/git_test.go +++ b/pkg/cli/git_test.go @@ -23,6 +23,28 @@ import ( // - TestStageWorkflowChanges (tests staging behavior during workflow compilation) // - TestStageGitAttributesIfChanged (tests conditional staging during compilation) +func TestIsSafeGitRevisionArg(t *testing.T) { + tests := []struct { + name string + ref string + want bool + }{ + {"empty", "", false}, + {"leading dash", "-oops", false}, + {"leading double dash", "--upload-pack=evil", false}, + {"plain branch", "main", true}, + {"remote branch", "origin/main", true}, + {"contains dash not leading", "feature-branch", true}, + {"short sha", "abc1234", true}, + {"fully qualified ref", "refs/heads/main", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, isSafeGitRevisionArg(tt.ref)) + }) + } +} + func TestGetCurrentBranch(t *testing.T) { tmpDir := testutil.TempDir(t, "test-*") From 8562188bb9ce49749af637b328cfc54fd6b49d98 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 06:19:45 +0000 Subject: [PATCH 3/3] Address git revision review feedback Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com> --- pkg/cli/git.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/cli/git.go b/pkg/cli/git.go index 8faebf1332e..5a36512fea0 100644 --- a/pkg/cli/git.go +++ b/pkg/cli/git.go @@ -19,10 +19,9 @@ import ( var gitLog = logger.New("cli:git") -// isSafeGitRevisionArg reports whether ref is safe to pass as a git revision -// argument (e.g. to "git log ..HEAD" or "git show :"). -// It rejects empty values and values starting with "-", which could -// otherwise be misinterpreted as command-line options (flag injection). +// isSafeGitRevisionArg reports whether ref cannot be misinterpreted as a git +// CLI flag by rejecting empty strings and values starting with "-". It does +// not validate that ref is a well-formed git revision. func isSafeGitRevisionArg(ref string) bool { return ref != "" && !strings.HasPrefix(ref, "-") } @@ -699,7 +698,7 @@ func checkWorkflowFileStatus(workflowPath string) (*WorkflowFileStatus, error) { if !isSafeGitRevisionArg(upstream) { gitLog.Printf("Rejecting unsafe upstream ref: %q", upstream) - return status, nil // Ignore unexpected/unsafe upstream ref, return current status + return status, fmt.Errorf("unexpected upstream ref %q", upstream) } // Check if there are commits in the current branch that affect this file and aren't in upstream