Skip to content

Guard git command arguments against flag injection (Sighthound findings) - #52401

Open
pelikhan with Copilot wants to merge 3 commits into
mainfrom
copilot/sighthound-fix-security-findings
Open

Guard git command arguments against flag injection (Sighthound findings)#52401
pelikhan with Copilot wants to merge 3 commits into
mainfrom
copilot/sighthound-fix-security-findings

Conversation

Copilot AI commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Sighthound flagged 5 critical CWE-78/89 findings across pkg/cli. Two exec.Command call sites concatenate git-derived values (ref, upstream) directly into revision-range/object arguments without validating they can't be interpreted as CLI flags.

Changes

  • New helper: isSafeGitRevisionArg(ref string) bool in pkg/cli/git.go — rejects empty strings and values starting with -, preventing them from being misread as options by git.
  • Applied validation:
    • checkWorkflowFileStatus (pkg/cli/git.go) now validates upstream before building upstream+"..HEAD" for git log.
    • gitRefExists and loadLocalMetricEvalResults (pkg/cli/experiments_command.go) now validate ref before building ref+":"+file for git show; rejection is logged for observability.
  • Tests: TestIsSafeGitRevisionArg covering empty, leading-dash, branch, remote-branch, SHA, and fully-qualified ref inputs.

Triaged as false positives / already mitigated (no change)

  • pkg/cli/forecast.go:78 — flagged line is a fmt.Fprintln log statement, not an exec sink.
  • pkg/cli/bootstrap_profile_github_app.go:286 — OAuth code is already validated via isBootstrapGitHubAppManifestCode; no SQL sink exists.
  • pkg/cli/grant.go:184imageRef, grantImageRef, and mount paths are already validated via validateDockerImageRef/validateContainerMountPath/buildDockerReadonlyFileMount, with an existing #nosec justification.
// before
cmd := exec.Command("git", "show", ref+":"+constants.EvalsResultFilename)

// after
if !isSafeGitRevisionArg(ref) {
    experimentsLog.Printf("Rejecting unsafe git ref: %q", ref)
    return nil
}
cmd := exec.Command("git", "show", ref+":"+constants.EvalsResultFilename)

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 15.4 AIC · ⌖ 5.31 AIC · ⊞ 8.5K ·
Comment /souschef to run again

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix security findings in github/gh-aw Guard git command arguments against flag injection (Sighthound findings) Aug 13, 2026
Copilot AI requested a review from pelikhan August 13, 2026 03:16
@pelikhan
pelikhan marked this pull request as ready for review August 13, 2026 04:11
Copilot AI balanced review requested due to automatic review settings August 13, 2026 04:11
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Ponytail Reviewer completed successfully!

Lean already. Ship.

Generated by Ponytail Reviewer for #52401

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #52401 does not have the 'implementation' label and has only 42 new lines of code in business logic directories (threshold: 100).

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict

I don't see a blocking issue in the changed lines.

Review notes

The new guard is narrow but correctly placed on the call sites that build git revision arguments, and the tests cover the intended leading-dash cases. I did not find a changed-line regression or an obviously missing error path that would justify blocking this PR.

I also attempted to collect the advisory sub-agent output, but no result was available at review time, so this verdict is based on my own pass over the diff.

🔎 Code quality review by PR Code Quality Reviewer · gpt54 · 3.56 AIC · ⌖ 4.55 AIC · ⊞ 6.5K
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Guard git command arguments against flag injection

This is a clean, well-scoped security fix. The isSafeGitRevisionArg helper correctly guards against flag injection (leading - turning refs into CLI flags). Guards are applied consistently at all three callsites, with appropriate logging and graceful fallbacks. Test coverage is solid.

No blocking issues found.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 18.4 AIC · ⌖ 6.27 AIC · ⊞ 5.4K

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel analysis complete: Score 100/100. Single table-driven test comprehensively validates security boundary (isSafeGitRevisionArg). Test covers 8 scenarios (empty, leading dashes, valid refs). No violations. Ready for approval.

🧪 Test quality analysis by Test Quality Sentinel

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds validation to prevent Git revision arguments from being interpreted as command-line flags.

Changes:

  • Adds a reusable Git revision safety check.
  • Validates upstream and experiment refs before Git execution.
  • Adds table-driven validation tests.
Show a summary per file
File Description
pkg/cli/git.go Adds revision validation and guards upstream refs.
pkg/cli/experiments_command.go Guards refs used by git show and git rev-parse.
pkg/cli/git_test.go Tests safe and unsafe revision inputs.

Review details

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 3/3 changed files
  • Comments generated: 0
  • Review effort level: Balanced

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — commenting only; no blocking issues.

📋 Key Themes & Highlights

Key Themes

  • Doc/name precision: isSafeGitRevisionArg implies broader validation than it delivers (flag-injection guard only). The comment should be tightened to avoid false confidence in future callers.
  • Silent failure path: checkWorkflowFileStatus returns the current status without an error when the upstream ref is unsafe, which may silently suppress the diff check from the caller's perspective. Returning an error keeps the caller in control.
  • Missing rejection tests for callers: TestIsSafeGitRevisionArg covers the helper well, but the rejection paths in loadLocalMetricEvalResults and gitRefExists have no dedicated tests.

Positive Highlights

  • ✅ Minimal, surgical fix — only adds guards, no churn
  • ✅ Good test coverage for the helper itself (TestIsSafeGitRevisionArg), including leading-dash and double-dash cases
  • ✅ Rejection is logged for observability in experiments_command.go
  • ✅ Accurate triage of false positives in the PR description

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 22.1 AIC · ⌖ 6.86 AIC · ⊞ 7K
Comment /matt to run again

Comment thread pkg/cli/git.go
// argument (e.g. to "git log <ref>..HEAD" or "git show <ref>:<path>").
// It rejects empty values and values starting with "-", which could
// otherwise be misinterpreted as command-line options (flag injection).
func isSafeGitRevisionArg(ref string) bool {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/diagnosing-bugs] The function name and comment say "safe git revision arg" but the implementation only blocks leading-dash flag injection — it does not validate rev syntax. This over-broad name may invite callers to rely on a guarantee it doesn't provide.

💡 Suggestion

Narrow the doc comment to the actual invariant:

// isSafeGitRevisionArg reports whether ref cannot be misinterpreted as a
// git CLI flag (non-empty, no leading dash). It does NOT validate that
// ref is a well-formed git revision.

This prevents future callers from treating it as a full validation gate.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the helper comment in 8562188 to state the exact invariant: it rejects empty and dash-prefixed values to prevent flag interpretation, but does not validate Git revision syntax.

Comment thread pkg/cli/git.go
if !isSafeGitRevisionArg(upstream) {
gitLog.Printf("Rejecting unsafe upstream ref: %q", upstream)
return status, nil // Ignore unexpected/unsafe upstream ref, return current status
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/diagnosing-bugs] On an unsafe upstream ref the function silently returns the current status with no error. Callers that rely on the returned status to decide whether to alert the user will silently skip the diff check — potentially hiding real workflow drift.

💡 Suggestion

Return a wrapped error so the caller can decide how to surface it:

if !isSafeGitRevisionArg(upstream) {
    return status, fmt.Errorf("unexpected upstream ref %q", upstream)
}

The caller can then log a warning and fall through gracefully, rather than silently losing the check.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated checkWorkflowFileStatus in 8562188 to return an explicit unexpected upstream ref error instead of silently returning the partial status.

}
ref = branchName
}
if !isSafeGitRevisionArg(ref) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] loadLocalMetricEvalResults returns nil on an unsafe ref, but no test covers this path. A regression could re-open the injection vector silently.

💡 Suggested test skeleton
func TestLoadLocalMetricEvalResultsRejectsUnsafeRef(t *testing.T) {
    // A leading-dash ref must not reach exec.Command
    result := loadLocalMetricEvalResults("--evil")
    assert.Nil(t, result, "expected nil for unsafe ref")
}

Combine with a spy/mock on exec.Command to assert the command is never invoked.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No caller-path test added: workflowID is always prefixed by WorkflowStateBranchName and then origin/, so loadLocalMetricEvalResults("--evil") cannot produce a dash-leading Git argument or exercise this guard. The security invariant itself remains directly covered by TestIsSafeGitRevisionArg.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 100/100 Excellent

Summary

PR adds a focused, high-quality security test for the isSafeGitRevisionArg() function that guards against flag-injection vulnerabilities in git command execution.

Test Analysis

TestIsSafeGitRevisionArg: Table-driven test with 8 scenarios

  • ✓ Design contract test (security boundary)
  • ✓ Edge cases: empty, leading -, leading --, valid refs
  • ✓ 8 parameterized assertions via subtests
  • ✓ Build tag: (go/redacted):build !integration
  • ✓ No mock libraries or inflation

Metrics

  • Implementation tests: 0% (threshold: ≤30%) ✓
  • Test inflation: 1.69:1 (threshold: ≤2:1) ✓
  • No coding violations ✓

Approval: Comprehensive security test with excellent behavioral coverage.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Please inspect the latest branch state, refresh the branch if needed, and run the pr-finisher skill before handing this PR back to maintainers.

No unresolved review threads were found.
No failed checks were reported in the compact candidate set for this run.
Branch update was requested automatically for this run when GitHub allows it.

Run context: https://github.com/github/gh-aw/actions/runs/31671853647

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 15.4 AIC · ⌖ 5.31 AIC · ⊞ 8.5K ·
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Please inspect the latest branch state, refresh the branch if needed, and run the pr-finisher skill before handing this PR back to maintainers.

No unresolved review threads were found....

Ran pr-finisher, confirmed the branch is current with main, and pushed 8562188 addressing the actionable review feedback. Local fmt, lint, targeted tests, impacted unit tests, full tests, and recompilation pass. Three review threads were replied to but remain unresolved because the available tooling does not expose thread resolution; maintainer resolution/approval and a CI re-trigger are still needed.

@github-actions

Copy link
Copy Markdown
Contributor

PR Triage

Category: bug | Risk: medium | Priority: high | Score: 83/100

Score breakdown: impact 40/50, urgency 28/30, quality 15/20

CI: green

Recommended action: fast_track

Security hardening (flag injection); multiple review comments from copilot-swe-agent self-review to address.

Automated triage — run 52401

Generated by 🔧 PR Triage Agent · auto · 67.2 AIC · ⌖ 2.77 AIC · ⊞ 7.8K ·

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[sighthound] Security findings in github/gh-aw

4 participants