People reach for rbash expecting a jail and get a speed bump instead, and that gap is where the real risk sits. This builds a restricted Bash login that runs approved commands, gives you a repeatable test for its limits, and draws a clear line around what rbash does not protect: about 20 minutes for a test account and a small command directory.
/etc need an administrator; the inspection and test commands do not.This guide describes GNU Bash 5.2.21, installed here as Debian package bash 5.2.21-2ubuntu4.
Security boundary: rbash is a convenience restriction, not a sandbox. It doesn't confine a process, remove dangerous programs, or stop a user finding another way to execute code. Use a container, a narrowly scoped service account, MAC policy, or a separate host when you actually need isolation.
On this installation, rbash is a symbolic link to Bash. Bash enters restricted mode when it starts under the name rbash, or when it gets -r or --restricted. Check the path and version before trusting any example:
$ command -v rbash
/usr/bin/rbash
$ ls -l /usr/bin/rbash
lrwxrwxrwx ... /usr/bin/rbash -> bash
$ bash --version | head -n 1
GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)
The exact link metadata varies between distributions. What matters: the command resolves, and the implementation behind it is the Bash version you've documented.
Don't experiment on the account you use for administration. As root, create a named account with a home directory and /usr/bin/rbash as its login shell. Replace restricted-demo with a deliberately obvious local name:
# useradd --create-home --shell /usr/bin/rbash restricted-demo
# passwd restricted-demo
useradd and passwd change system state, so a disposable virtual machine is the safer place to test authentication or startup files. To undo this test account later, first make sure it owns no data you need, then run as root:
# userdel --remove restricted-demo
Warning: that removal is destructive. It deletes the account's home directory, so copy out anything you intentionally created before using it.
A restricted shell can't change PATH once restrictions are active, so set it in the account's startup environment or its login service. Keep only directories with commands the account genuinely needs. A private directory owned by root and not writable by the restricted user is an easy test setup:
# install --directory --owner=root --group=root --mode=0755 /home/restricted-demo/bin
# ln -s /usr/bin/printf /home/restricted-demo/bin/printf
# ln -s /usr/bin/id /home/restricted-demo/bin/id
# chown root:root /home/restricted-demo/.bash_profile
# chmod 0644 /home/restricted-demo/.bash_profile
Put this content in /home/restricted-demo/.bash_profile:
PATH=/home/restricted-demo/bin
export PATH
The account needs to read its profile and traverse the directories, but must never be able to replace the profile, the command directory, or the command files themselves. A writable command directory turns PATH into a route for swapping out an approved program.
Checkpoint: log in as the test user and run printf '%s\n' "$PATH" and id:
$ printf '%s\n' "$PATH"
/home/restricted-demo/bin
$ id
uid=... (restricted-demo) gid=... (restricted-demo) groups=...
If PATH is empty or has unexpected directories, stop and fix the login setup before testing restrictions. Don't try to patch it with export PATH=... inside rbash; setting or unsetting PATH is forbidden there.
For a quick local test, start a clean restricted shell. --noprofile --norc keeps unrelated startup files out of this particular test; they're Bash options, not a way to configure a production login:
$ rbash --noprofile --norc
-bash: ...
Inside that shell, the following should all fail:
$ cd /tmp
-bash: cd: restricted
$ /bin/echo hello
-bash: /bin/echo: restricted: cannot specify `/' in command names
$ printf hello > /tmp/output
-bash: /tmp/output: restricted: cannot redirect output
The prompt and error wording can vary. What you're checking: changing directory, a slash in a command name, and redirecting output all get rejected. Exit with exit, or Ctrl-D.
The Bash manual defines a specific list.
cd, changing SHELL, PATH, HISTFILE, ENV or BASH_ENV, and any command name containing /.., history and hash -p builtins.SHELLOPTS from the environment at startup.exec, adding or deleting builtins with enable -f and enable -d, enabling disabled builtins, and command -p.set +r and shopt -u restricted_shell do nothing to lift the mode.These controls cut down accidental navigation and command selection. They do not turn an ordinary command into a safe one. If an approved command can launch a pager, interpreter, editor, networking client, or anything that accepts a command string, the user may well reach capabilities outside your intended menu. Review every executable in the PATH as carefully as you'd review a small privileged service.
Here's the boundary that's easy to miss: when rbash executes a shell script, the shell spawned to run that script has restrictions turned off. That doesn't mean every script is unrestricted in every detail, but it's enough to kill the idea that a script wrapper is a security boundary.
Demonstrate it with a harmless child shell:
$ rbash --noprofile --norc -c 'bash -c '\''printf "child flags: %s\n" "$-"'\'''
child flags: hBcn
The child's flags don't include r, while the restricted shell's do. Treat any executable script available to the account as trusted code. If you need a fixed operation, prefer a small compiled helper or a service interface with operating-system permissions and input validation, then test it as an untrusted caller would use it.
Test every approved command with the real account, not just as root. Check its arguments, what it can read and write, environment handling, subprocess behaviour, and any escape features. Confirm the account can't write its own startup files or the command directory. Keep logs and authentication policy outside anything the user can write to.
Don't grant sudo to compensate for a missing command. A sudo rule can turn the restricted account into a route to administrative access, especially when the permitted program can execute another command or load a configuration file. If elevated work is genuinely required, design and audit that separately.
/usr/bin/rbash.