Skip to content

Fix command-line argument injection in Diff action (CVSS 8.6) - #29

Merged
baudronp merged 2 commits into
mainfrom
fix/difftool-arg-injection
Oct 1, 2026
Merged

baudronp merged 2 commits into
mainfrom
fix/difftool-arg-injection

Conversation

@jontdelorme

Copy link
Copy Markdown
Contributor

Summary

Fixes a command-line argument injection vulnerability in the Diff action (DiffFileChangeAction) that let a crafted repository execute arbitrary programs on the victim's machine.

Vulnerability

git difftool was invoked with a path built by directly interpolating the file's name into the argument string, unquoted:

var args = $"difftool -y {_commitId}^ {_commitId} {path}";

ProcessStartInfo.Arguments is parsed like a shell command line. A file (or renamed-from path) named, e.g., payload --extcmd=wscript.exe would split into two arguments once whitespace-delimited: payload and --extcmd=wscript.exe. Git then parses the latter as a real --extcmd option, running an attacker-chosen program with the victim's OS privileges — triggered simply by opening the crafted repo and clicking the normal Diff button.

Fix

  • Quote each path argument so a filename (including one containing spaces or leading dashes) is always treated as a single literal token.
  • Insert -- before the paths so git treats everything after it as positional paths, never options — defense in depth even if quoting were somehow bypassed.
  • Extracted the argument-building logic into GitHelpers.BuildDiffToolArguments (Core project) so it's unit-testable independent of the WPF UI project.

Testing

Added GitTimelapseView.Tests/GitHelpersTests.cs with regression tests, including one using the exact payload from the report (payload --extcmd=wscript.exe), asserting the malicious text always stays inside a single quoted path placed after --.

  • dotnet test GitTimelapseView.Tests/GitTimelapseView.Tests.csproj → 5/5 passed
  • dotnet build GitTimelapseView/GitTimelapseView.csproj → build succeeded, 0 warnings/errors

🤖 Generated with Claude Code

jontdelorme and others added 2 commits September 30, 2026 11:41
A crafted filename such as "payload --extcmd=wscript.exe" was
interpolated unquoted into the git difftool argument string. Since
ProcessStartInfo.Arguments is parsed as a whitespace-delimited command
line, the filename split into two arguments, letting git interpret
--extcmd (or --ext-diff/-x) as a real option and execute an
attacker-chosen program with the victim's privileges when they clicked
Diff on a crafted repository.

Fix by quoting the path arguments and inserting -- before them so git
always treats them as positional paths, never as options.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Extract the difftool argument-building logic into
GitHelpers.BuildDiffToolArguments so it is unit-testable without
pulling WPF dependencies into the test project, and add tests that
exercise the crafted-filename payload from the report (e.g.
"payload --extcmd=wscript.exe") to confirm it is always kept as a
single quoted, positional path after '--' and never parsed as a git
option.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@baudronp
baudronp merged commit 49d8ccd into main Oct 1, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants