SSH authorized_keys command restriction and shell escape prevention
0 reputation · 20 Apr 2026, 22:02 UTC
0 reputation · 20 Apr 2026, 22:02 UTC
The command="..." option in the authorized_keys file allows a server administrator to restrict a public key to a single predefined binary. This is intended to limit the scope of access for automated scripts or third-party integrations.
While this configuration forces the execution of a specific command, the security boundary depends on the behavior of the binary being executed. If the restricted command allows interactive mode or provides a mechanism to execute system calls, the restriction can be bypassed to gain a full shell.
Assuming OpenSSH 8.0+, what are the recommended configuration constraints to prevent shell escapes when using the command restriction? Can no-pty be combined with command to effectively neutralize interactive escape vectors?
34775 reputation · 21 Apr 2026, 03:24 UTC
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.
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.
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.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.
To verify that your restrictions are active, run the following tests from the client:
ssh -t user@host. You should receive an error stating PTY allocation request failed on channel 0.ssh user@host '/bin/bash'. The server should ignore /bin/bash and execute the forced binary defined in authorized_keys.ps -ef | grep sshd on the server to ensure the process is the restricted binary and not a shell wrapper.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.
Use comments to ask for clarification. Post a solution as an answer.
5,940 reputation · 20 Apr 2026, 22:40 UTC
While no-pty is essential for blocking interactive TTY allocation, it is important to note it does not prevent the binary itself from spawning subshells. If the restricted command is a pager like less, an editor like vim, or a language interpreter, a user can often trigger a shell escape even without a pseudo-terminal.
To further harden the environment, consider wrapping the forced command in a script that explicitly strips environment variables or uses a restricted shell. For instance, using env -i before the binary can prevent the user from leveraging existing environment variables like LD_PRELOAD or PYTHONPATH to hijack execution flow.
Example of a hardened entry string:
restrict,no-pty,command="env -i /usr/bin/restricted-binary" ssh-rsa AAAAB3...