Using limited environments correctly, without a false sense of security
The restricted shell rbash blocks cd, PATH changes, and calling programs through a path containing a slash. That is enough for simple, benign restrictions like an SFTP replacement, but it can be bypassed with documented techniques relatively easily. Anyone using rbash should know exactly what it covers and what needs additional hardening.
Table of Contents
- 1. What a restricted shell is and what it is meant for
- 2. What exactly gets restricted: cd, PATH, programs with a slash
- 3. Typical use case: limited SSH access for contractors
- 4. Setting up an rbash environment correctly
- 5. Known escape techniques: why rbash alone is not enough
- 6. Hardening rbash sensibly: additional layers instead of relying on one
- 7. When a real alternative to rbash is the better choice
- 8. Common mistakes when operating rbash environments
- 9. rbash compared to other isolation mechanisms
- 10. Summary
- 11. FAQ
1. What a restricted shell is and what it is meant for
A restricted shell is a Bash variant that blocks a fixed set of actions before any command even runs. It is activated either through the symlink or command name rbash, the startup flag bash -r, or by setting the restricted option at runtime with set -r. All three paths lead to the same restricted mode, only the timing of activation differs.
The purpose of a restricted shell is not to replace a full sandbox system, but to prevent benign misuse and to limit a user's range of action within a clearly defined, usually already trusted context. Typical use cases are a limited login for an external contractor who should only run one fixed script, or an SFTP-like access where the user should not move freely through the filesystem.
2. What exactly gets restricted: cd, PATH, programs with a slash
In an rbash session, the following actions are specifically forbidden: changing directory with cd, changing the variables PATH, SHELL, ENV, or BASH_ENV, running commands whose name contains a slash (such as /bin/bash or ./script.sh), and redirecting output into a new file with >, >>, or >|. Even turning off restricted mode itself via set +r is blocked once it is active.
This list already shows the underlying principle: rbash does not forbid specific commands directly, it restricts the ways a user can invoke programs outside a predefined PATH and manipulate files outside allowed directories. Programs located inside the allowed PATH keep running perfectly normally, which is why the contents of that directory form the actual security boundary, not the shell itself.
# Minimal rbash setup for a restricted account
useradd -m -s /bin/rbash deploy-partner
mkdir -p /home/deploy-partner/bin
ln -s /usr/bin/rsync /home/deploy-partner/bin/rsync
# Only this directory is exposed via PATH, set in the user's profile
echo 'PATH=$HOME/bin' >> /home/deploy-partner/.bash_profile
echo 'export PATH' >> /home/deploy-partner/.bash_profile
chmod 555 /home/deploy-partner/bin # not writable by the user
3. Typical use case: limited SSH access for contractors
A common scenario is an external contractor who should only run a specific deployment script over SSH, without getting free shell access to the server. Combined with the SSH option ForceCommand in sshd_config, or directly in the authorized_keys file via command="...", the login can be limited to exactly one command, while rbash additionally prevents that command from loading arbitrary other programs internally.
The order of these defenses matters: ForceCommand decides what runs at all upon login, and rbash then restricts what that command itself is still allowed to do if it becomes interactive or opens a subshell. Both mechanisms together are considerably more robust than either alone, because ForceCommand prevents a direct shell login from the start and rbash additionally limits the range of action inside the allowed command.
# In /home/deploy-partner/.ssh/authorized_keys
command="/home/deploy-partner/bin/deploy.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA... partner@example.com
# In sshd_config, alternative per-user ForceCommand
Match User deploy-partner
ForceCommand /home/deploy-partner/bin/deploy.sh
ChrootDirectory /home/deploy-partner
4. Setting up an rbash environment correctly
The most important step during setup is pointing PATH to a single directory, not writable by the user, containing only vetted programs, and setting that PATH in a profile file the user can no longer modify. If PATH is instead set interactively or in a file the user can write to, they can simply overwrite it on the next login before rbash even applies.
In addition, every script inside the exposed directory should be written defensively: no calling external programs with user-controlled arguments, no eval calls on user input, and where possible, avoiding shell interpreters in favor of statically compiled wrapper programs. rbash restricts the shell itself, but it does not control what the exposed programs do internally with their own arguments.
5. Known escape techniques: why rbash alone is not enough
rbash has been known for years for a whole range of documented escape routes. Programs that can start an interactive shell themselves, such as vi with :!bash, less with !bash, or ftp, scp, and similar tools with built-in shell escapes, completely defeat the restricted shell as soon as they sit inside the exposed PATH. Options like ssh -o ProxyCommand=..., or redirecting script execution via source, can also break out of the restriction in certain configurations.
Another known route is that rbash only forbids the user from directly running a program via a slash path, but an already-allowed program in PATH can still open its own path containing a slash internally, for example an editor that reads or writes arbitrary paths through its own file-open feature. That is exactly why the ground rule is: only expose programs proven to offer no shell escapes, no filesystem navigation, and no subprocess calls with free-form arguments.
6. Hardening rbash sensibly: additional layers instead of relying on one
Because rbash alone is not a hard security boundary, it belongs in a layered concept: a chroot environment or a Linux namespace additionally limits which files are even visible, regardless of whether an escape from rbash succeeds. On systems running systemd, services can be further hardened with NoNewPrivileges, ProtectSystem, and similar sandbox directives that stay effective even after a successful rbash escape.
For SSH access, it is also recommended to place the user in a dedicated group without sudo rights, set the home directory restrictively (chmod 750), and regularly audit which binaries actually live in the exposed PATH. An rbash setup that never gets reviewed tends to accumulate extra, accidentally exposed programs over time, which opens new escape routes.
# Combine rbash with a minimal chroot for an SFTP-only user
usermod -d /home/partner -s /bin/rbash partner
# In sshd_config: chroot plus internal-sftp, no rbash escape possible
# because there is no shell at all inside the jail
Match User partner
ChrootDirectory /home/partner
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
7. When a real alternative to rbash is the better choice
For pure file transfer, OpenSSH's internal-sftp combined with ChrootDirectory is almost always the more robust solution, because it never starts a shell at all, which eliminates the entire class of rbash escapes from the start. For a single, clearly defined command, a plain ForceCommand without rbash is often sufficient, as long as the command itself does not offer an interactive subshell.
For more strongly isolated environments, containers with a minimal root filesystem or dedicated jump hosts with strict audit logging are the noticeably more robust choice compared to any form of restricted shell, because they isolate at the kernel level rather than the application level. rbash remains a useful, lightweight building block, but not the sole line of defense for security-critical access.
8. Common mistakes when operating rbash environments
A frequent operational mistake is leaving an interactive login script like .bashrc or .bash_profile writable for the restricted user. Since rbash forbids changing PATH at runtime but not editing the profile file itself, a user with write access to their own home directory can freely extend PATH on the next login and effectively lift the restriction.
A second common mistake is placing an overly powerful program inside the exposed PATH, such as a generic text editor or an archiving tool with a built-in shell feature, without first carefully checking its full feature set. Every additional program in a restricted shell's PATH enlarges the attack surface, which is why the list of allowed programs should be kept as small as possible.
9. rbash compared to other isolation mechanisms
rbash differs from chroot, containers, and namespaces mainly in the attack vector it protects against: rbash controls which shell features may be used, while chroot and containers control which files and resources are even visible in the first place. Both layers complement each other but do not replace one another, which is why production setups usually combine several of these mechanisms.
The table below places rbash alongside the most common alternatives and shows which mechanism fits which level of required isolation, from simple misuse prevention up to complete process isolation.
| Mechanism | Isolation level | Protection against escapes | Typical use |
|---|---|---|---|
| rbash | Shell features (cd, PATH, redirect) | Weak, documented escapes exist | Misuse prevention, simple SSH access |
| internal-sftp + chroot | Filesystem, no shell | Very strong, no shell present | Pure file transfer without commands |
| ForceCommand | Allowed command at login | Medium, depends on the command | Running exactly one fixed script |
| Linux namespace/container | Kernel resources (PID, network, filesystem) | Strong, kernel-enforced | Fully isolated environments |
| systemd sandboxing | Process capabilities, file access | Strong, complements other layers | Services with reduced privileges |
Mironsoft
Shell automation, DevOps tooling and deployment infrastructure
Shell scripts that hold up in production?
We review existing Bash scripts, spot fragile patterns and replace them with robust Bash patterns: complete error handling, logging and safe parallelization for your deployment stack.
Code Review
ShellCheck analysis and manual review for critical Bash pattern violations.
Refactoring
Retrofitting error handling, logging and safe file operations.
CI Integration
Wiring ShellCheck and BATS into pipelines and building regression tests.
10. Summary
Restricted Shell (rbash): The Essentials at a Glance
Activation
bash -r, the rbash command, or set -r at runtime all put the shell into restricted mode with the same limitations.
Restrictions
Changing cd, PATH/SHELL/ENV, running programs with a slash in the name, and redirecting output into new files are all blocked.
Escapes
Programs with a built-in shell feature like vi, less, or scp defeat rbash as soon as they sit inside the exposed PATH.
Recommendation
Combine rbash with chroot, ForceCommand, and regular PATH audits, never use it as the sole security boundary.