reported on 5 June 2026 https://github.com/cyanheads/git-mcp-server/security/advisories/GHSA-265x-r5m8-w5v2 - no response, so trying here:
Summary
The ref/object parameters of several read tools (git_log branch, git_diff source/target, git_show object) are typed as a plain string with no leading-dash or format validation, and are placed into the git command line as positional arguments. git therefore interprets a value beginning with "-" as an option. Using git's --output= option, an attacker who can influence these parameters can write git output to an arbitrary file outside the repository (and other git option-injection effects). git_log is even annotated readOnlyHint: true but writes a file. Confirmed on 2.15.1: git_log with branch="--output=/tmp/...txt" wrote a file outside the repository.
Details
The ref schema is z.string().min(1) with no validation, src/mcp-server/tools/schemas/common.ts (around line 69). The values are pushed raw into the git argv before the "--" separator:
- git_log: branch pushed at src/services/git/providers/cli/operations/commits/log.ts (around line 85), before the "--" at line 90.
- git_diff: source/target -> commit1/commit2 at .../commits/diff.ts (around lines 48, 52).
- git_show: object at .../commits/show.ts (around line 113).
The argument validator does not stop this: validateGitArgs allows any --flag=value and its unknown-flag throw is commented out, src/services/git/providers/cli/utils/command-builder.ts (around lines 223-233). In stdio mode the scope/auth check defaults to allowed (transports/auth/lib/authUtils.ts around lines 30-36). So a "-"-prefixed ref reaches git as an option.
PoC
validated on @cyanheads/git-mcp-server 2.15.1 over MCP stdio against a local repo:
git_log present: true
git_log result: { "success": true, "commits": [], ... }
OOB file written outside repo: true | ARG-INJECTION: CONFIRMED
The tool call git_log({ path: "", branch: "--output=/tmp/GITMCP_LOG_OOB.txt" }) caused git to write its log output to /tmp/GITMCP_LOG_OOB.txt, outside the repository. git_diff({ source: "--output=/tmp/...", target: "HEAD" }) and git_show with a "--output=" object behave the same. The clone tool's url field also has no protocol validation (ext::sh ... is forwarded to git), so on git builds where protocol.ext.allow is permissive, clone becomes command execution; on default git it is blocked, but the --output file-write injection above is not config-dependent.
Impact
An attacker who can influence the ref/object arguments (LLM-produced, prompt-injection steerable) can write git output to an arbitrary file the process can write, overwriting files outside the repository (configuration, data, or, combined with the writable content, more serious targets). git's many options (for example --output, and via other tools -O/--upload-pack/-c) provide additional primitives. The readOnlyHint on git_log is misleading.
Remediation
Validate ref/object/branch/remote parameters: reject values beginning with "-" (or pass them only after a "--" separator and never as options), and apply an allowlist/format check (a valid ref/commit/branch pattern). Re-enable the unknown-flag rejection in validateGitArgs. Treat all string parameters that reach the git command line as potentially option-injecting.
reported on 5 June 2026 https://github.com/cyanheads/git-mcp-server/security/advisories/GHSA-265x-r5m8-w5v2 - no response, so trying here:
Summary
The ref/object parameters of several read tools (git_log branch, git_diff source/target, git_show object) are typed as a plain string with no leading-dash or format validation, and are placed into the git command line as positional arguments. git therefore interprets a value beginning with "-" as an option. Using git's --output= option, an attacker who can influence these parameters can write git output to an arbitrary file outside the repository (and other git option-injection effects). git_log is even annotated readOnlyHint: true but writes a file. Confirmed on 2.15.1: git_log with branch="--output=/tmp/...txt" wrote a file outside the repository.
Details
The ref schema is z.string().min(1) with no validation, src/mcp-server/tools/schemas/common.ts (around line 69). The values are pushed raw into the git argv before the "--" separator:
The argument validator does not stop this: validateGitArgs allows any --flag=value and its unknown-flag throw is commented out, src/services/git/providers/cli/utils/command-builder.ts (around lines 223-233). In stdio mode the scope/auth check defaults to allowed (transports/auth/lib/authUtils.ts around lines 30-36). So a "-"-prefixed ref reaches git as an option.
PoC
validated on @cyanheads/git-mcp-server 2.15.1 over MCP stdio against a local repo:
The tool call git_log({ path: "", branch: "--output=/tmp/GITMCP_LOG_OOB.txt" }) caused git to write its log output to /tmp/GITMCP_LOG_OOB.txt, outside the repository. git_diff({ source: "--output=/tmp/...", target: "HEAD" }) and git_show with a "--output=" object behave the same. The clone tool's url field also has no protocol validation (ext::sh ... is forwarded to git), so on git builds where protocol.ext.allow is permissive, clone becomes command execution; on default git it is blocked, but the --output file-write injection above is not config-dependent.
Impact
An attacker who can influence the ref/object arguments (LLM-produced, prompt-injection steerable) can write git output to an arbitrary file the process can write, overwriting files outside the repository (configuration, data, or, combined with the writable content, more serious targets). git's many options (for example --output, and via other tools -O/--upload-pack/-c) provide additional primitives. The readOnlyHint on git_log is misleading.
Remediation
Validate ref/object/branch/remote parameters: reject values beginning with "-" (or pass them only after a "--" separator and never as options), and apply an allowlist/format check (a valid ref/commit/branch pattern). Re-enable the unknown-flag rejection in validateGitArgs. Treat all string parameters that reach the git command line as potentially option-injecting.