BoundBench

MCP Git server

Reference MCP server for local git repo read/manipulation

github.com/modelcontextprotocol/servers › src/git · 2026-10-03 · f46d957

Defense-in-depth score

3.9 / 10

Minimal

A small, narrowly built git server: no shell, no network tools, no credentials, accurate read/write annotations on every tool, and careful checks against flag injection and path traversal. Its weak points are defaults and visibility: with no --repository flag it can act on every git repository the user owns, it keeps no record of what it did, and it bounds none of its output. The dominant risk is indirect: git_commit and git_checkout run the repository's git hooks on the host as the user, so a repository whose hooks execute tracked code can turn a routine commit into arbitrary code execution.

Key gaps (1)

  1. git_commit and git_checkout run the repository's git hooks on the host as the OS user with the full environment; nothing isolates them or disables hooks (impact inferred from GitPython/git behaviour). C4 · Code-execution isolation

Criteria

C1 Identity & least privilege

Minimal 0.17 / 1.00

The server holds no credentials of its own and never forwards tokens, but it runs with the full authority of the OS user who launched it and does nothing to narrow that. Its only authorization check is an optional repository restriction; with the CLI default (no --repository) every git repository the user can reach on disk is fair game. Git subprocesses inherit the full environment, so any git credential helpers or SSH agents configured for the user remain reachable by git and its hooks. Because the server exposes no push, fetch, or network tool, a hijack is limited to local git writes.

C2 Approval gates

Moderate 0.63 / 1.00

As a tool server, the git server can't approve anything itself, but it gives the host what it needs to gate actions: reads and writes are separate tools and all twelve carry accurate read-only/destructive annotations that nothing at runtime can change. It offers no dry-run or preview for its write operations and no server-enforced read-only mode. Write actions are local and mostly reversible through git itself, but committing and checking out run whatever git hooks the repository has installed, which the approver is not told about.

C3 Tool & action scoping

Minimal 0.47 / 1.00

The tools are narrow git operations rather than a generic git or shell passthrough, and arguments get real checks: refs must resolve in the repository, values starting with '-' are rejected to stop flag injection, files passed to git_add must resolve inside the repository, and the MCP SDK validates argument types against each tool's schema. The repository-path allowlist resolves symlinks properly, but it is off unless the operator passes --repository, and the advertised MCP 'roots' list is never enforced. Numeric arguments such as log count and diff context are unbounded, and every write tool is always enabled.

C4 Code-execution isolation

Minimal 0.38 / 1.00

The server never runs a shell or evaluates model text: it calls git through GitPython with argument lists. But git_commit and git_checkout run the repository's installed git hooks, and with common setups (pre-commit framework, husky-style tracked hooks directories) those hooks execute code that comes from the repository's working tree, on the host, as the user, with the full environment. There is no isolation in the default uvx/pip install. The optional Docker image adds a plain container, but it runs as root, and the README's leading Docker example mounts the user's whole home directory.

C5 Untrusted input blast radius

Minimal 0.17 / 1.00

Everything the server returns comes straight from the repository: commit messages, diffs, file contents, branch names, authored by anyone who has contributed. It hands this back as plain text with a short label and no marker that it is untrusted, and attacker-written commit messages are inlined verbatim in git_log. The server itself has no network egress and no irreversible action, so a hijacked host can use it only for local, reversible git changes, plus whatever the repository's hooks do when it commits. It offers no read-only or no-egress mode a host could use to break the Rule of Two.

C6 Memory, context & configuration integrity

Minimal 0.35 / 1.00

The server keeps no memory and loads no configuration or instruction files of its own. The one persistence path a hijacked model controls is the repository itself: commit messages and branch names it writes stay in the history and come back, unmarked, through git_log, git_show, and git_branch in later sessions. That history is easy for a person to inspect but the server offers no way to remove what was written. Git itself still honours repository config, attributes, and hooks, but the server neither adds nor restricts that.

C7 Third-party extensions

N/A · full credit 1.00 / 1.00

The server loads no plugins, downloads no tools, and launches no other servers: its only runtime dependencies are pinned in the lockfile and installed by the user. There is no extension surface to compromise.

C8 Secrets & sensitive-data protection

Minimal 0.45 / 1.00

The server accepts no API keys or tokens, sends nothing to telemetry, and logs almost nothing (no tool arguments or outputs), so there is little for it to leak. It also has no redaction: secrets committed to a repository flow back to the model unfiltered through diffs and git_show, and git and its hooks receive the user's full environment.

C9 Audit & traceability

Minimal 0.00 / 1.00

The server keeps no record of the tool calls it executes: no arguments, results, or timestamps are logged at any level. Git's own reflog records some ref changes, but that is git's bookkeeping inside the repository, not an audit trail the server writes. After an incident, you would have to rely on the host's logs.

C10 Limits & kill switch

Minimal 0.25 / 1.00

The server bounds almost none of its own work. git_log defaults to ten commits but the caller can raise it at will, and diffs, git_show output, status, and branch listings are unbounded in size. No git call has a timeout, and the server offers no rate limiting or cancellation of an in-flight operation beyond the host killing the process.