git over SSH always fails when sandboxed: injected GIT_SSH_COMMAND ProxyCommand omits proxy credentials

Status Open
Reported on v2.1.237
Maintainer reply None cached
Activity 0 comments · opened Oct 1, 2026

Summary

With sandboxing enabled, every git-over-SSH operation fails (push, fetch, pull, clone,
ls-remote). Claude Code injects a GIT_SSH_COMMAND that routes SSH through the sandbox-runtime
SOCKS5 proxy, but the ProxyCommand offers no proxy credentials — and the proxy requires
authentication, so it refuses the connection.

There is no user-side workaround, and listing ssh / git push in sandbox.excludedCommands does
not help, because the env var is inherited by unsandboxed commands too.

Environment

  • Claude Code 2.1.237
  • macOS 26.6.2, arm64 (Darwin 25.6.0)
  • sandbox.enabled: true, sandbox.allowUnsandboxedCommands: false
  • sandbox.excludedCommands: ["ssh", "git push", "git fetch", "git pull", "git clone", "git ls-remote"]
  • bitbucket.org and github.com both present in sandbox.network.allowedDomains

What happens

Any git-over-SSH command dies immediately:

$ git push -u origin my-branch
ssh_dispatch_run_fatal: Connection to UNKNOWN port 65535: Broken pipe
fatal: Could not read from remote repository.

UNKNOWN port 65535 is the signature of a ProxyCommand pipe rather than a real socket —
getpeername() has nothing to report.

Root cause

Claude Code injects this into the Bash environment:

GIT_SSH_COMMAND=ssh -o ControlMaster=no -o ControlPath=none \
  -o ProxyCommand='nc -X 5 -x localhost:<PORT> %h %p'

The nc -X 5 -x SOCKS5 hop sends no credentials. But the sibling proxy variables in the same
environment do carry them:

HTTPS_PROXY=http://srt.<REDACTED>:<REDACTED>@localhost:<PORT>
ALL_PROXY=http://srt.<REDACTED>:<REDACTED>@localhost:<PORT>

Dialing the SOCKS hop by hand reproduces the refusal — the proxy answers with a spoofed SSH banner:

$ nc -X 5 -x localhost:<PORT> -w 6 bitbucket.org 22 < /dev/null | strings -n 8
SSH-2.0-policy_refusal
This proxy requires authentication, and this client did not offer an authentication method, so the connection was refused.
error = 0 61

Why there is no workaround

  • nc on macOS has no SOCKS username/password option (no -P in this build), so the injected

ProxyCommand cannot authenticate even in principle.

  • socat, ncat, connect, and corkscrew are all absent by default, so there is no alternative

authenticating SOCKS client to substitute.

  • GIT_SSH_COMMAND takes precedence over core.sshCommand, so a user cannot override the transport

through git config. (It also silently discards -o LogLevel/-vvv overrides, which makes this
hard to diagnose — no debug1 output ever appears.)

  • The variable is inherited whether or not a command is sandboxed, so sandbox.excludedCommands

does not restore SSH.

  • HTTPS git operations work fine, because https_proxy carries the credentials. The breakage is

specific to the SSH path.

Expected behaviour

The injected ProxyCommand should authenticate to the proxy it is pointed at — e.g. reuse the
credentials already present in ALL_PROXY/HTTPS_PROXY with a SOCKS client that supports
user/pass auth, or use an HTTP CONNECT proxy command with Basic auth.

Reproduction

  1. In settings.json, set sandbox.enabled: true and add a git host to

sandbox.network.allowedDomains.

  1. Ask Claude to run git ls-remote git@bitbucket.org:<org>/<repo>.git HEAD.
  2. Observe ssh_dispatch_run_fatal: ... Broken pipe.
  3. Confirm the cause with nc -X 5 -x localhost:<PORT> -w 6 bitbucket.org 22 < /dev/null | strings.

Secondary observation

It is unclear whether sandbox.excludedCommands is honoured when
sandbox.allowUnsandboxedCommands: false. A bare ssh -T git@bitbucket.org (which ignores
GIT_SSH_COMMAND) still gets a hard DNS policy denial:

$ ssh -T git@bitbucket.org
ssh: Could not resolve hostname bitbucket.org: -65563

...despite ssh being listed in excludedCommands, while the /config panel describes strict mode
as: "All bash commands invoked by the model must run in the sandbox unless they are explicitly
listed in excludedCommands
." Either the exclusion is not applying, or the description is
misleading about what the flag does.

View original on GitHub ↗