Codex Desktop Remote SSH: unbounded reconnect loop leaks pwsh.exe on Windows host until it hard-freezes (1299 processes, 95% commit, 2 forced reboots)

Open 💬 1 comment Opened Jul 12, 2026 by openhe-hub

Summary

When a remote SSH connection ("Connections" / remote machine) added in Codex Desktop fails to bootstrap against a Windows OpenSSH host, Codex retries the connection roughly every 90 seconds, forever, with no retry cap and no backoff. Each attempt spawns a pwsh.exe (+ conhost.exe) on the Windows host that never exits. Over ~1.5 days this accumulated to:

  • 1299 × pwsh.exe and 1302 × conhost.exe
  • ~43.26 GB of private memory held by PowerShell processes
  • System commit charge 104.2 / 109.6 GB (95%), ~0.6 GB free of 32 GB physical RAM
  • A paging/disk-I/O storm (single system-disk writes taking 36–260 s), Windows services timing out at 30 s, then SSH, ping and the whole machine becoming unresponsive

The Windows host hard-froze twice (Jul 11 ~01:54 and ~14:03 local time) and had to be power-reset. After each reboot the leak immediately started accumulating again, because the Desktop app kept retrying. The only mitigation was deleting the connection from the Codex Desktop app.

The client side leaks too: on the macOS machine running Codex Desktop, each retry orphaned the ProxyJump tunnel process, leaving 34+ ssh -W [host]:22 <jumphost> processes with PPID 1 accumulated over ~30 hours.

This effectively turns a misconfigured/failed connection into a remote denial-of-service against the user's own machine.

Environment

  • Client (machine A): macOS (Apple Silicon), ChatGPT desktop app 26.707.41301 (bundled codex-cli 0.144.0-alpha.4); standalone app-server ~/.codex/packages/standalone/current is codex-cli 0.144.1
  • Remote (machine B): Windows 11, 32 GB RAM, native Windows OpenSSH, default shell resolves to PowerShell 7 (pwsh.exe)
  • SSH route: client → jump host (Linux) → Windows host, via ProxyJump in ~/.ssh/config

Steps to reproduce

  1. On machine A (macOS), have Codex Desktop set up and working.
  2. Add machine B — a Windows host whose OpenSSH default shell is PowerShell — as a remote SSH connection in Codex Desktop.
  3. The bootstrap fails (expected, see #22757 / #22965 — the POSIX login-shell probe is sent to PowerShell).
  4. Leave the connection configured. Codex Desktop retries ~every 90 s indefinitely.
  5. On the Windows host, watch pwsh.exe count grow monotonically; each process's command line contains the bootstrap probe:

``
Codex remote SSH requires SHELL to point to an executable login shell
``

  1. Within ~24–36 h the host exhausts commit charge and freezes.

The exact probe command observed (client side)

ssh -T -v -o BatchMode=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=12 <host> sh -c 'if [ -z "$SHELL" ] || [ ! -x "$SHELL" ]; then echo "Codex remote SSH requires SHELL to point to an executable login shell" >&2; exit 127; fi; ... exec /bin/sh -c "$CODEX_REMOTE_PAYLOAD" ...' sh '...; PATH="${CODEX_INSTALL_DIR:-$HOME/.local/bin}:$PATH"; export PATH; codex app-server proxy'

On Windows, OpenSSH hands this to pwsh.exe, which fails to parse it — but the spawned pwsh.exe/conhost.exe pair is never torn down when the SSH session ends, and Codex never stops retrying.

Expected behavior

  • Retries should be capped and/or use exponential backoff, and stop (with a visible error) after repeated bootstrap failures of the same kind — a deterministic exit 127 / parse failure will never succeed on retry.
  • Each attempt must clean up after itself: the remote pwsh.exe/conhost.exe and the local ProxyJump ssh -W child should be terminated when the attempt fails or times out.

Actual behavior

  • Infinite ~90 s retry loop that survives for days.
  • Every attempt leaks one pwsh.exe + conhost.exe on the Windows host and (intermittently) one orphaned ssh -W on the macOS client.
  • The Windows host is driven into commit exhaustion → paging storm → complete freeze requiring power reset, repeatedly, until the user manually deletes the connection.

Diagnostics collected on the Windows host (before mitigation)

  • 1299 pwsh.exe, 1302 conhost.exe, all with near-identical command lines containing the bootstrap probe string
  • PowerShell private memory total ≈ 43.26 GB; commit 104.2/109.6 GB (95%); free physical ≈ 0.6 GB / 32 GB
  • Event log: mass 30 s service timeouts; system disk writes taking 36–260 s
  • No bluescreen/bugcheck codes; SSD SMART healthy, 43 °C — consistent with resource exhaustion, not hardware failure

Cleanup that worked (after deleting the connection on the client):

Get-CimInstance Win32_Process -Filter "Name='pwsh.exe'" |
  Where-Object { $_.CommandLine -like '*Codex remote SSH requires SHELL*' } |
  ForEach-Object { Stop-Process -Id $_.ProcessId -Force }

Related issues

  • #22757 — Remote SSH to Windows OpenSSH fails when default shell is PowerShell (the failure mode that triggers this loop)
  • #22965 — Remote SSH to native Windows host bootstrap assumes POSIX shell

Those cover the connection failure; this issue is about the unbounded retry + process leak that turns that failure into a machine-killing resource exhaustion on both ends.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗