Skip to content

ssh -t exec path concatenates the command unquoted — GNU-style -c shells lose all but the first word #2478

Open
PowerShell/openssh-portable
#889

Description

"OpenSSH for Windows" version: 9.5p1 (in-box Optional Feature)

Server / Client OS: Windows 10 19045

What is failing

When a pty is allocated (ssh -t), do_exec_windows builds the shell
command line by plain concatenation in contrib/win32/win32compat/w32-doexec.c:

// pty path
strcpy_s(pty_cmd, len, shell);                       // "\"<shell path>\""
strcat_s(pty_cmd, len, " ");
strcat_s(pty_cmd, len, shell_command_option_local);  // "-c"
strcat_s(pty_cmd, len, " ");
strcat_s(pty_cmd, len, command);                     // NOT quoted

This produces "C:\shell.exe" -c echo a b. Any shell whose -c takes a
single operand (GNU semantics — bash, and other bash-compatible shells)
then runs echo with a b demoted to $0/$1: the command silently
truncates to its first word.

The non-pty path immediately below does quote:

sprintf_s(posix_cmd_input, len, "%s %s \"%s\"", shell, option, exec_command);

Repro

Set a GNU-style shell as DefaultShell (e.g. Git Bash bash.exe or
Niubash niu.exe) with DefaultShellCommandOption = -c, then:

ssh -tt host 'whoami'          → works (single word)
ssh -tt host 'sleep 30'        → "sleep: missing operand"   (30 lost)
ssh -tt host 'printf ok123'    → "printf: usage: ..."       (ok123 lost)
ssh -tt host 'echo x > f.txt'  → bare echo; redirect never reaches the shell
ssh -tt host 'cmd /c echo x'   → an interactive cmd prompt  (args dropped)

The same commands work fine without -t, confirming the quoting
discrepancy between the two branches. cmd.exe and powershell.exe are not
affected because their /c/-c consume the rest of the command line —
which is presumably why this has gone unnoticed.

Expected

ssh -tt host 'sleep 30' runs sleep 30, same as without a pty.

Suggested fix

Quote the command operand in the pty branch (with proper
CommandLineToArgvW escaping for embedded quotes/backslashes), e.g.
append "%s" — noting that merely wrapping in quotes is not sufficient
for commands that already contain quotes; the escaping rules used by
build_exec_command/the non-pty path should be mirrored.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions