To prevent shell escapes when using the command="..." restriction in OpenSSH 8.0+, you must combine the forced command with options that disable terminal allocation and network tunneling. The no-pty option is highly effective at neutralizing interactive escape vectors, but it is not a complete security boundary on its own.
Recommended Configuration Constraints
The most secure approach is to use the restrict keyword (introduced in OpenSSH 7.2), which acts as a shorthand for several critical security constraints. This prevents the user from requesting a PTY, forwarding ports, or using X11/agent forwarding.
The Hardened authorized_keys Entry
Use the following format for your authorized_keys file to isolate a specific binary:
restrict,command="/usr/bin/restricted-binary" ssh-rsa AAAAB3... user@host
If your version of OpenSSH does not support restrict, manually specify the following constraints:
no-pty: Prevents the allocation of a pseudo-terminal, blocking interactive shells (e.g., vim :sh or python pty.spawn).
no-port-forwarding: Prevents the user from using the SSH session as a tunnel to other internal services.
no-X11-forwarding: Disables X11 graphics tunneling.
no-agent-forwarding: Prevents the user from accessing the local SSH agent.
no-user-rc: Prevents the execution of ~/.ssh/rc upon login.
The Role of no-pty in Escape Prevention
Combining no-pty with command effectively neutralizes interactive escape vectors. Most shell-escape techniques rely on a TTY to provide an interactive prompt. Without a PTY, the binary cannot easily transition into an interactive shell session that the client can control.
Important: no-pty does not prevent non-interactive escapes. If the restricted binary itself is vulnerable (e.g., it contains a buffer overflow or an eval statement that processes SSH_ORIGINAL_COMMAND), an attacker can still execute arbitrary code or system calls without needing a terminal.
Verification Steps
To verify that your restrictions are active, run the following tests from the client:
- Test PTY Block: Run
ssh -t user@host. You should receive an error stating PTY allocation request failed on channel 0.
- Test Command Override: Run
ssh user@host '/bin/bash'. The server should ignore /bin/bash and execute the forced binary defined in authorized_keys.
- Verify Process: While the connection is active, run
ps -ef | grep sshd on the server to ensure the process is the restricted binary and not a shell wrapper.
Missing Diagnostic Detail
Does the restricted binary accept any user-supplied arguments or environment variables? If the binary processes SSH_ORIGINAL_COMMAND, the security of the restriction depends entirely on the binary's input validation logic rather than the SSH configuration.