[Desktop] SSH sessions: remote server probes SSH_AUTH_SOCK with empty connections on every spawn, killing a forwarded Windows OpenSSH agent

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

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Setup: Claude Desktop on Windows 11, Code tab, with an SSH connection to a VS Code Dev Container. The container runs sshd, and VS Code Dev Containers forwards the Windows OpenSSH Authentication Agent into it as /tmp/vscode-ssh-auth-<uuid>.sock. A login-shell profile script exports that socket as SSH_AUTH_SOCK.

Symptom: Within minutes of using a Desktop SSH session, the Windows ssh-agent stops accepting connections. The ssh-agent service stays Running, but \\.\pipe\openssh-ssh-agent disappears. Every agent client then fails: the container, VS Code, and Windows itself. Recovery takes Restart-Service ssh-agent plus a full VS Code restart, and the fault comes back with the next few Desktop git refreshes.

This started with the Desktop update of 2026-09-24 (remote server f6010b97…, ccd-cli 2.1.281). It still reproduces on remote server c8e2f083a63593e9adf0bbebc99debff07a5545f with ccd-cli 2.1.295 (2026-10-12).

Cause: Desktop asks the remote server to spawn processes for session start and for every git status and diff refresh. If a spawn's environment has no SSH_AUTH_SOCK, the server reads the login shell's SSH_AUTH_SOCK and checks that it is alive. It does this by connecting and closing without sending a byte (agentSocketSource.Live, probeLoginShellAgentSocket), once per spawn. One git refresh is 8–17 spawns, so 8–17 empty connections arrive in under a second.

VS Code relays each connection to a connect and close on the Windows named pipe. Win32-OpenSSH's listener does not survive that burst. Process Monitor shows Code.exe CreateFile and CloseFile on \Device\NamedPipe\openssh-ssh-agent with no WriteFile, then PIPE NOT AVAILABLE retries. The agent's FSCTL_PIPE_LISTEN then returns PIPE CLOSING, and the agent stops listening for good.

That listener fragility is a Win32-OpenSSH bug (reproduced on inbox 9.5 and on 10.0.0.0p2-Preview). But this probe is the only client that produces the pattern. Real agent clients such as ssh-add -l and git over ssh send a request on every connection, and they don't trigger it.

Evidence:

  • The probe is the server's. A logging relay in front of the socket (SO_PEERCRED) attributed the connections to ~/.claude/remote/srv/<hash>/server --serve: about 9 connections in 0.5 s, 0 bytes each way, about 4 s after each spawn.
  • Diff refreshes reproduce it. Opening the diff pane three times: ssh-add -l works after the first burst and fails with communication with agent failed after the second or third.
  • It happens in normal use. The agent was alive at 08:37:33 and dead by 08:40:06. Over those 3 minutes the command=git spawn count in remote-server.log rose from 8 to 40.
  • Users can't turn it off. SpawnParams has a disableShellAgentSocket field, but the Windows app never sets it (no reference in its app.asar). The session connection forces ForwardAgent off, so the server never has an SSH_AUTH_SOCK of its own that would skip the probe.

What Should Happen?

A Desktop SSH session should not make the user's SSH agent unusable. Any of these would fix it:

  1. Probe with a real request or not at all. Check liveness with SSH2_AGENTC_REQUEST_IDENTITIES (what ssh-add -l sends) rather than a bare connect, or skip the check and let a dead socket fail in the consumer.
  2. Probe less often. Check once and cache the result rather than once per spawned process. Skip app-internal git that never talks to a remote (status, diff).
  3. Expose an opt-out, for example a per-connection sshConfigs field that sets disableShellAgentSocket.

Error Messages/Logs

~/.claude/remote/run/<id>/remote-server.log
2026/10/12 08:37:09 [shellenv] The login shell exports SSH_AUTH_SOCK=/tmp/vscode-ssh-auth-<uuid>.sock
2026/10/12 08:37:09 [process.Manager] Process … started, PID=…, command=git    (8 in the same second)

Container, minutes later:
$ ssh-add -l
error fetching identities: communication with agent failed

Windows:
PS> Test-Path \\.\pipe\openssh-ssh-agent
False
PS> (Get-Service ssh-agent).Status
Running

Steps to Reproduce

  1. On Windows 11, run the OpenSSH Authentication Agent with a key loaded.
  2. Open a folder in a VS Code Dev Container that runs sshd. VS Code forwards the agent as /tmp/vscode-ssh-auth-<uuid>.sock.
  3. In the container, make login shells export that socket, for example /etc/profile.d/ with export SSH_AUTH_SOCK=/tmp/vscode-ssh-auth-<uuid>.sock.
  4. In Claude Desktop, add an SSH connection to the container's sshd and start a Code session there.
  5. Open or refresh the diff pane two or three times.
  6. In the container, run ssh-add -l: it fails with communication with agent failed. On Windows, Test-Path \\.\pipe\openssh-ssh-agent returns False.

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

The Desktop build before the 2026-09-24 remote-server update (f6010b97…, ccd-cli 2.1.281)

Claude Code Version

ccd-cli 2.1.295 (remote), Claude Desktop 2.31226.1 (857652) 2026-10-09T17:56:07.000Z

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Other

Additional Information

  • Related: #29717 (SSH_AUTH_SOCK in Desktop SSH sessions; this probe may be what fixed it), #68057 (a local-side agent probe on macOS), #96661 (app-initiated git uses the agent with no opt-out).
  • Host-side workarounds:
  • Tested: a container-side relay that connects upstream only on a client's first byte absorbs the probes. We ran it for a day.
  • Not yet tested live: sshd SetEnv SSH_AUTH_SOCK=… should make the server skip the probe, because the spawn environment would then already have the variable.

Both depend on internals, which is why we'd like a supported fix.

View original on GitHub ↗