Join our Newsletter — 33% off our NHI Course
Home› Guides› Restricted Shells Guide: rbash, Forced Commands and Why…
Guide Privileged Access (PAM)

Restricted Shells Guide: rbash, Forced Commands and Why Shell Escapes Keep Working

PDF for newsletter subscribers · free to read online

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 11 November 2026 12 min read
On this page

Restricted shells promise to let someone log in to a server but only do a few things, and in practice that promise breaks the moment any allowed program can start another program. Administrators still reach for rbash, rssh, custom menus and sudo rules on editors to give contractors, support staff, backup jobs and file-transfer partners "limited" access, and penetration testers still walk out of them routinely. The GNU Bash manual itself calls restricted mode only one component of a restricted environment. This guide explains what rbash actually restricts, why shell escapes keep working, and which mechanisms hold up better: SSH forced commands with restrict, internal-sftp with ChrootDirectory, purpose-built shells such as git-shell, sudo NOEXEC and INTERCEPT, and isolation through containers or jump hosts. It is written for Linux and Unix administrators, platform engineers and the people who review their access designs.

Key takeaways

  • rbash is a convenience, not a boundary. It blocks cd, slashes in command names, output redirection and changes to PATH, but any permitted program with a shell escape undoes all of it.
  • The allowed command list is the real attack surface. Editors, pagers, interpreters, find, scp and rsync can all run other programs; GTFOBins catalogues hundreds of such binaries.
  • Forced commands are stronger, if you close the side doors. OpenSSH ForceCommand and command= ignore what the client asks for, but do not stop port, agent or X11 forwarding unless you add restrict or DisableForwarding.
  • Prefer a mechanism built for the job. internal-sftp in a chroot for file transfer, git-shell for Git, a single-purpose script for automation, a container or jump host for anything interactive.
  • Assume escape and limit the blast radius. The restricted account should have nothing worth stealing: no sudo, no readable secrets, no writable paths in other users' trust chains, and full session logging.

What rbash actually restricts

Bash enters restricted mode when it is started as rbash or with -r or --restricted. The Bash 5.3 manual page lists what is disallowed or not performed:

RestrictionWhat it stopsWhat it does not stop
No cdChanging directory in the shellPrograms that open files by path on their own
Cannot set or unset SHELL, PATH, HISTFILE, ENV or BASH_ENVPointing PATH at a directory of the user's choosingVariables not on the list, such as VISUAL, EDITOR or PAGER, which change what allowed programs launch
No command names containing a slashRunning /bin/sh directlyAllowed programs that run a shell internally
No slash in filenames for ., history and hash -p; no -p for . or commandSourcing or hashing arbitrary pathsPrograms that read configuration from the home directory
No output redirection (>, >>, >|, <>, >&, &>)Writing files from the shellAllowed programs that write files (editors, tee, scp)
No exec, no enable changes, no importing functions or BASHOPTS and SHELLOPTS from the environmentReplacing the shell or loading builtinsAnything outside the shell process
Cannot turn off restricted mode (set +r, shopt -u restricted_shell)Simple self-releaseA new, unrestricted shell started by another program

Two details catch people out. Restrictions apply only after startup files are read, so a user who can write ~/.bashrc or ~/.bash_profile controls the session. And when rbash runs a command that turns out to be a shell script, the manual says restrictions are turned off in the shell spawned to run it. The manual's own advice is to set PATH to a small set of verified commands, move the user to a non-writable directory other than home, block shell scripts, clear variables such as VISUAL and PAGER, and use jails, zones or containers where stronger separation is needed.

Why shell escapes keep working

A shell escape is any feature of an allowed program that starts another program, writes a file that will later be executed, or reads a file the user should not see. These are ordinary features, not bugs, which is why they survive patching. GTFOBins, the community catalogue of Unix binaries that can bypass local restrictions on misconfigured systems, classifies them into functions including Shell, Command, File read, File write, Upload, Download and Library load, and contexts including Unprivileged, Sudo, SUID and Capabilities. It states it is not a list of exploits but of legitimate functions.

Class of allowed programWhy it escapesSafer alternative
Editors (vi, vim, nano, emacs)Run external commands and open any readable filesudoedit scoped to named files, or a web or API workflow
Pagers (less, more, man)Run commands and open an editor (VISUAL, EDITOR)Output to the client without a pager; set PAGER to a fixed safe value
Interpreters (python, perl, awk, lua)Full programming language with process and file APIsNever allow; wrap the needed task in a fixed script
File tools (find, tar, zip, rsync, scp)Options that run commands or load codeinternal-sftp in a chroot; fixed rsync command with validated arguments
Network tools (ssh, curl, wget)Load configuration and proxy commands; move files in and outDo not allow on restricted accounts
Custom menus and wrapper scriptsUnquoted input passed to a shell, or calls to the programs aboveFixed command set, no user-controlled arguments, reviewed like any privileged code

Purpose-built restricted shells fail the same way. rssh, which limited SSH users to scp, sftp, rsync and similar, had CVE-2019-1000018 (command execution through its allowscp permission) and CVE-2019-3463 and CVE-2019-3464 (rsync argument and environment variable bypasses). When the ESnet security team reported the scp issue, the author replied that rssh is no longer maintained. Any system still using it should migrate. For the defensive view of these techniques see the Linux Privilege Escalation Techniques Guide.

Mechanisms compared

MechanismGood forStrengthMain caveat
rbash with a curated PATHReducing accidents by trusted usersLowAny escape in an allowed binary defeats it
SSH ForceCommand (sshd_config, in a Match block)Accounts or groups that should run one thingMedium to highRuns through the user's login shell with -c; forwarding must be disabled separately
command= with restrict in authorized_keysAutomation keys: backups, deploy hooks, monitoringHigh for that keyThe wrapper script must validate SSH_ORIGINAL_COMMAND safely
internal-sftp plus ChrootDirectoryFile transfer partners and uploadsHighChroot path must be root-owned and not writable by group or others
git-shellGit-only SSH accessHighA git-shell-commands directory enables custom and interactive commands
sudo with NOEXEC, INTERCEPT or sudoeditDelegated admin tasksMedium to highNOEXEC only covers dynamically linked programs on supporting systems
Container, VM or jump host sessionInteractive support accessHighMore to build and run; still needs identity, logging and least privilege

SSH forced commands done properly

  • Behaviour: sshd_config(5) says ForceCommand ignores any command supplied by the client and ~/.ssh/rc, and applies to shell, command and subsystem requests. The original request is available to the wrapper in SSH_ORIGINAL_COMMAND.
  • Close the side channels: the same manual warns that ForceCommand does not limit TCP, agent, socket or X11 forwarding. Use DisableForwarding yes and PermitTTY no in the Match block. For per-key restrictions in authorized_keys, sshd(8) defines restrict, which disables port, agent and X11 forwarding, PTY allocation and ~/.ssh/rc, and will include future restrictions.
  • Why it matters: OpenSSH's 2016 X11 forwarding advisory (CVE-2016-3115, fixed in 7.2p2) showed that injected xauth commands could get around ForceCommand, authorized_keys command restrictions and restricted shells when X11 forwarding was enabled. Its recommended mitigation was X11Forwarding no and restrict or no-x11-forwarding on restricted keys.
  • Wrapper scripts: treat SSH_ORIGINAL_COMMAND as untrusted input. Match it against an exact allow list and run fixed commands; never pass it to eval or an unquoted shell expansion. See the Secure Bash and Shell Scripting Guide.
  • Login shell: because the forced command runs through the account's login shell, set that shell to a plain, root-owned shell and make the home directory and its dotfiles non-writable by the user.

sudo controls for allowed programs

The sudoers manual describes two tags for programs that can start other programs. NOEXEC prevents a dynamically linked program from running further commands, where sudo and the operating system support it; the manual's example applies it to more and vi. INTERCEPT instead validates every child command against the sudoers policy and logs it, at some performance cost and with limits on set-user-ID programs. For editing system files, sudoedit scoped to named files avoids running an editor as root at all. See the sudo and sudoers Security Guide.

How to implement

  1. Inventory restricted access: find accounts whose login shell is rbash, rssh, a menu script or similar, every Match block with ForceCommand, and every authorized_keys entry with command=. See How to Find ssh authorized keys across a server fleet.
  2. Write down the purpose of each: file transfer, Git, a single automated task, or interactive support. The purpose decides the mechanism from the table above.
  3. Replace the weakest first: rssh and rbash accounts used by external parties, then menu scripts, then forced commands missing restrict or DisableForwarding.
  4. Pilot on one host: deploy the new configuration with sshd -t to validate syntax, keep an existing root session open, and test both the intended task and a set of denied actions (interactive shell, port forward, agent forward, file outside the chroot).
  5. Roll out by group: use Match Group blocks so you can move accounts between old and new configurations by group membership, which also makes rollback a group change rather than an edit under pressure.
  6. Test escapes, not just function: include restricted accounts in authorised penetration tests and ask testers to report every escape route, not just the first.

Where identity fits

Most restricted SSH access today belongs to non-human identities: backup agents, deployment pipelines, monitoring collectors and partner file transfers, each with a key in an authorized_keys file. Those keys rarely expire and are often copied between systems. A forced command with restrict and a from= source address limit is the minimum for each one; short-lived SSH certificates issued per job are better. Each key needs an owner, a purpose and a review date. See the SSH Key Management Guide and the Linux Service Accounts and Keytab Management Guide.

Detection and measurement

  • Process lineage: alert when a restricted account's session produces a shell or interpreter process (sh, bash, python, perl) whose parent is an editor, pager or file tool. Linux auditd execve rules or an EDR agent provide the data. See the Linux Logging and auditd for Defenders Guide.
  • SSH channel requests: log and alert on refused forwarding or PTY requests from restricted accounts, which often show probing.
  • Configuration drift: monitor sshd_config, authorized_keys and dotfiles in restricted homes with file integrity monitoring.
  • Metrics: number of accounts on rbash or rssh (target zero for external users); percentage of command= keys that also carry restrict and from=; percentage of ForceCommand blocks with forwarding disabled; escapes found per penetration test; restricted accounts with sudo rights (target zero).

Framework mapping

FrameworkReferenceHow it applies
NIST SP 800-53 Rev. 5AC-3, AC-6Access enforcement and least privilege for limited accounts
NIST SP 800-53 Rev. 5CM-7, CM-7(2)Least functionality and preventing program execution beyond what is needed
NIST SP 800-53 Rev. 5AC-17, AU-12Remote access controls and audit record generation for sessions
NIST CSF 2.0PR.AA-05, PR.PS-01, DE.CM-03Least-privilege permissions, configuration management, monitoring of personnel activity
ISO/IEC 27001:2022 Annex AA.8.2, A.8.18Privileged access rights; use of privileged utility programs
CIS Controls v8.1Control 5, Control 6Account management and access control management
MITRE ATT&CK v20T1059.004 Unix Shell, T1548.003 Sudo and Sudo CachingWhat a successful escape produces, and abuse of sudo rules on escape-capable programs

Common failure patterns

  • Allowing one "harmless" editor or pager: it turns rbash back into a full shell. If users need to edit, use sudoedit or a managed workflow.
  • Writable home and dotfiles: the user edits ~/.bashrc or adds files to a PATH directory, and restrictions never apply.
  • Forced command without restrict: the key cannot open a shell but can still forward ports into the internal network or use an agent, which is the gap CVE-2016-3115 and the sshd_config warning describe.
  • Still running rssh: an unmaintained tool with published bypasses guards external file transfer accounts.
  • Restricted account with secrets: SSH keys, cloud credentials or database passwords readable by the restricted user mean any escape becomes lateral movement. A jump host that holds such secrets is a high-value target; see If your jump host and bastion is compromised.
  • Testing only the happy path: the task works, so the configuration ships, without anyone trying the denied actions.

Practitioner checklist

  • Inventory accounts on rbash, rssh or menu shells, ForceCommand blocks and command= keys.
  • Migrate file transfer accounts to internal-sftp with a root-owned ChrootDirectory.
  • Add restrict and from= to every automation key with command=.
  • Set DisableForwarding yes and PermitTTY no in every Match block that uses ForceCommand.
  • Validate SSH_ORIGINAL_COMMAND against an exact allow list in wrapper scripts.
  • Remove editors, pagers, interpreters and file tools from restricted PATHs; use sudoedit, NOEXEC or INTERCEPT where delegation is required.
  • Make restricted home directories and dotfiles non-writable by the user.
  • Log process creation for restricted sessions and alert on shells spawned by allowed programs.
  • Retire rssh and replace custom menu scripts with single-purpose commands.
  • Include restricted accounts in penetration test scope with escape testing explicitly requested.

Standards and references

Related NHI Mgmt Group resources: SSH Key Management Guide · sudo and sudoers Security Guide · Linux Server Hardening Guide · Linux Privilege Escalation Techniques Guide · Terminal Escape Sequence Injection Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 11 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.