Skip to Content
DocsDashboardSettingsSecurityRestricted Shell Policy

Restricted Shell Policy

QuickBox Pro sandboxes standard (non-admin) users into a restricted shell built on lshell. It intercepts every command a limited user types and checks it against a whitelist before running it — so a seedbox user can manage their own torrents and files without being able to roam the server, chain commands, or escape to an interactive shell.

The Restricted Shell editor lives in the dashboard at Settings → Security → Restricted Shell and is the recommended way to tune that policy. It exposes the safe, user-facing fields of the lshell configuration as guarded form inputs, previews every change before it lands, and stores your edits in the shared database so they survive qb update — where a hand-edited /etc/lshell.conf would be overwritten.

Admin only

The Restricted Shell editor follows the standard Security Settings gates: admin.settings.read to view the policy, admin.settings.update to apply a change (or user level 9+). Writes are CSRF-protected. Navigate to Settings → Security → Restricted Shell from the sidebar.

This edits the policy, not who gets it

This page edits the shared restricted-shell policy — the command whitelist and hardening applied to every limited-shell user. To choose which shell level a specific user gets (sudo, full, or limited), use User Management → User Admin in the dashboard or qb user shell on the CLI.


What the editor does

Edits the safe fields

Ten user-facing policy fields (allowed and forbidden commands, over-SSH commands, SCP/SFTP, warnings, process cap, the shell banner, and aliases) are editable as guarded form inputs, and an Allowed folders section lets you add more folders restricted users can open

Locks the security fields

The log paths, the built-in folders every user is confined to, and the no-exec backstop are always rendered from the shipped base and cannot be removed or edited. Changing them would break confinement or the Fail2Ban jails

Previews before applying

A Preview action shows the current vs proposed policy and which fields changed, so nothing is written until you have seen the diff

Applies safely

The new config is round-trip parsed exactly as lshell reads it before it ever replaces the live file — a config that fails validation is never applied, so a bad edit can't lock every limited user out


Editable fields

These ten [default] fields are exposed as form inputs. Each input carries the same guard rails the server enforces on save, so the UI hints match what will actually be accepted.

FieldWhat it controlsGuard rails
Allowed commands
The command whitelist a limited user may run interactively
May never include a shell or shell-escape editor (sh, bash, dash, zsh, ksh, csh, tcsh, vi, vim)
Forbidden patterns
Tokens blocked anywhere in user input — command chaining, piping, redirection, subshells
Must be non-empty and must retain every required token: ; & | ` > < $( ${ sudo ./
Over-SSH commands
Commands allowed via non-interactive SSH (e.g. ssh user@host rsync ...)
Must be a subset of the effective Allowed list
Warning counter
Forbidden-command warnings before the session is terminated
1–10
Strict mode
When on, every forbidden token counts as a warning and is logged in the shape the Fail2Ban filter recognizes
On / off
SCP
Allow file transfer via SCP
On / off
SFTP
Allow the SFTP subsystem
On / off
Max processes
Per-user process/thread cap (RLIMIT_NPROC) that stops a fork bomb on a shared box
0 (disabled) or 100–10000
Intro banner
The welcome text shown when a limited user logs in
Free text
Aliases
Command aliases applied in the restricted shell (e.g. ll → ls -l)
Key/value pairs
The whitelist is the security boundary

Adding a command to Allowed gives every limited-shell user on the box that command. Keep the list tight — the default whitelist covers the torrent, file-management, and transfer tools a seedbox user needs and nothing more. The editor refuses to add any interactive shell or a text editor with a known shell-escape (like vi/vim), because those would let a user break out of confinement.


Allowed folders

Restricted users can only open folders on a short allow list. Every account always gets its own home folder and its own /opt folder. The Allowed folders section lets an admin add more folders on top of those, for example a shared storage mount.

ListWhat it holds
Always allowed (locked)
/home/<account> and /opt/<account>, where <account> is the user's own account name. Shown with a read-only badge. These always apply and cannot be removed
Additional folders
Folders you add. Up to 50 folders, each up to 255 characters. Remove one with the X beside it

To add a folder, type its absolute path into the New allowed folder path box and click Add folder (or press Enter). The folder is applied with the rest of your edits through the same Preview and Apply steps.

Use %u where each user’s own account name belongs. For example, /mnt/storage/%u gives every restricted user access to their own folder under /mnt/storage, and nothing else in it.

What a folder entry can be

  • It starts with / and has no trailing /.
  • Each folder name uses letters, digits, and . _ - @ only. No spaces, quotes, commas, or wildcards.
  • %u stands alone as a whole folder name.
  • No . or .. names and no //.

Folders that are refused

The server rejects an entry rather than quietly changing it, and the section shows why. These are never accepted:

  • The filesystem root /.
  • /home or /opt themselves, because that would open every account’s folder to every user. A folder inside them, such as /home/shared or /opt/shared, is fine.
  • System and QuickBox folders, including everything beneath them: /etc, /root, /boot, /proc, /sys, /dev, /run, /bin, /sbin, /lib, /lib32, /lib64, /usr, /var/lib, /var/log, /opt/quickbox, and /etc/v4-dashboard.
  • A folder that is a link (symlink) pointing into one of the protected locations above.
  • A folder already in the always-allowed list, or one you already added.
Preview warns when a folder is missing

If a folder does not exist on the server, or is not a folder, Preview shows a Review before applying warning. It does not block the change. Restricted users cannot use that entry until the folder exists. For an entry with %u, the check looks at the part of the path before %u, for example /mnt/storage for /mnt/storage/%u, so create that parent folder first.

File permissions still apply

Adding a folder lets restricted users open it from the limited shell. It does not give them read or write access. Normal file permissions on the folder still decide what each user can see and change, so set the owner, group, and mode on the folder to match who should use it.


Locked fields

These fields are always rendered from the shipped base config and are rejected if you try to send them as an edit. They are locked on purpose:

Locked fieldWhy it is locked
logpath, loglevel, logfilename
The Fail2Ban shell-confinement filters match against these exact log paths and levels. Changing them would silently break brute-force detection on the restricted shell
path, home_path, env_path, allowed_cmd_path
These confine a user to their own home and /opt folders and control which system directories are searched for command binaries, which is the core of the sandbox. The built-in folders in path cannot be removed or reordered. You can add folders after them in Allowed folders
path_noexec_strict
The no-exec backstop that stops a user executing arbitrary binaries. lshell fails closed at login if its supporting library is missing
history_file
The per-user command-history location, pinned to the user's home tree
Locked fields protect confinement and monitoring

The locked fields are not editable from the dashboard, the API, or a hand-edited config that the dashboard re-applies. They are what keeps a limited user inside their own folders (plus any you add under Allowed folders) and what keeps the Fail2Ban shell jails working. If a locked field is ever sent as an override, the server rejects the whole request rather than silently accept it.


Preview, then apply

Editing the policy is a two-step, no-surprises flow:

  1. Edit the fields you want to change. Each input validates against its guard rails as you type.
  2. Preview — the editor shows the current policy alongside the proposed one and lists exactly which fields changed. Nothing is written yet.
  3. Apply — the new configuration is validated the way lshell itself parses it, then atomically swapped in. If validation fails, the live config is left untouched and the errors are shown.
Live sessions keep the old policy until next login

Applying a new policy does not disturb users who are currently logged in — their session keeps the previous policy until they next log in. The change takes effect for each limited user on their next login.

Per-field revert to base

Every editable field can be reverted to the value QuickBox ships. The editor compares your saved policy against the pristine base, so you can drop a single override without resetting everything else. When you edit a value back to exactly the shipped base, that override is dropped automatically — it becomes a true “no override” rather than an override that happens to match.

Clearing all overrides resets the policy entirely to the shipped base.


Your edits survive qb update

The editor stores your changes as an override document in the shared database, not as a hand-edit of /etc/lshell.conf. That distinction matters:

  • /etc/lshell.conf is a derived file — QuickBox rebuilds it from the shipped base plus your overrides.
  • On every qb update, the pristine base config is re-copied over /etc/lshell.conf. A hand-edit made directly to that file would be lost.
  • Because your dashboard edits live in the database, the update pipeline re-applies them automatically after re-copying the base, so an edited policy persists across updates.
Prefer the editor over hand-editing /etc/lshell.conf

You can hand-edit /etc/lshell.conf on the server, but those edits are overwritten on the next qb update unless they are captured as dashboard overrides. For any change you want to keep, use the Restricted Shell editor (or the API) so it is stored durably and re-applied on update.


When to use the editor

Symptoms

  • A tool your users legitimately need (e.g. an added transfer or media utility) is being blocked in the limited shell
  • You want to tighten the whitelist and remove a command limited users no longer need
  • Fork bombs or runaway process counts are affecting a shared box and you want to lower the per-user process cap
  • You want a custom welcome banner for your seedbox users
  • You changed the policy directly on disk and it keeps reverting after an update

What to do

  • Open Settings → Security → Restricted Shell
  • Edit the Allowed, Forbidden, or hardening fields as needed
  • Click Preview and confirm only the fields you intended changed
  • Apply — the change is validated and swapped in atomically
  • Move any on-disk hand-edits into the editor so they survive qb update

Best practices

Do

  • Keep the Allowed whitelist as small as your users actually need — every command you add is granted to all limited-shell users.
  • Use Preview before every Apply and confirm only the fields you meant to change are listed.
  • Store policy changes through the editor (or the API) so they survive qb update.
  • Leave Strict mode on so forbidden commands are logged in the shape the Fail2Ban shell jails recognize.
  • Keep a sensible Max processes cap on shared boxes to contain fork bombs.
  • Add the narrowest folder that works, and use %u (for example /mnt/storage/%u) so each user only reaches their own folder.
  • Revert a single field to base with per-field revert instead of resetting the whole policy when you only need to undo one change.

Don't

  • Don't add an interactive shell (bash, sh, zsh) or a shell-escape editor (vi, vim) to Allowed — the editor rejects these because they break confinement.
  • Don't remove required tokens from the Forbidden list — chaining, piping, redirection, and sudo must stay blocked.
  • Don't hand-edit /etc/lshell.conf for changes you want to keep — they are overwritten on the next update.
  • Don't try to change the log paths or remove the built-in folders. They are locked to protect the sandbox and the Fail2Ban jails. To widen access, add a specific folder under Allowed folders instead.
  • Don't expect an added folder to grant access on its own. Normal file permissions still decide what users can read and write there.
  • Don't set Over-SSH commands that are not also in the Allowed list — the editor requires Over-SSH to be a subset.

FAQ

It applies to every user on shell level 3 (limited) — the default for standard seedbox users. Admins on shell level 1 (sudo) or 2 (full) get a normal bash shell and are not confined by lshell. You set a user's shell level from User Management → User Admin or with qb user shell -o sudo|full|limited.
Those are locked fields. The log paths are matched verbatim by the Fail2Ban shell-confinement jails, so changing them would silently break brute-force detection on the restricted shell. The built-in folders (each user's own /home/<account> and /opt/<account>) are what keep a user inside their own space. Removing them would compromise the sandbox, so the dashboard renders them from the shipped base and rejects any attempt to override them. You can still add more folders on top of them under Allowed folders.
Open Settings → Security → Restricted Shell, find the Allowed folders section, type the absolute path (for example /mnt/storage/%u), click Add folder, then Preview and Apply. %u stands for each user's own account name. The folder must exist on the server, and normal file permissions still decide what users can read and write in it.
The root /, /home or /opt themselves, protected system folders such as /etc, /usr and /root, and any link that points into one of them are never accepted. Entries with wildcards, spaces, quotes, .., or a trailing / are refused too. Use plain folder names made of letters, digits and . _ - @, with %u only as a whole name. The message under the box names the exact problem.
Check that the folder exists on the server. Preview shows a warning when it does not, and the entry has no effect until it does. For an entry with %u, create the folder before %u first (for example /mnt/storage). Then check the folder's owner and permissions: adding a folder lets users open it, but normal file permissions still decide what they can read. Users already logged in keep the old policy until their next login.
It won't apply. Before the live config is replaced, the proposed configuration is serialized and parsed exactly the way lshell reads it. If it fails that check, the live /etc/lshell.conf is left untouched and the editor shows the validation errors. A broken config would lock out every limited-shell user, so nothing that fails validation is ever written.
Yes. Edits made in the dashboard are stored as an override document in the shared database, not as a hand-edit of the config file. On qb update, the pristine base config is re-copied and then your overrides are re-applied automatically, so an edited policy persists. A change made by hand-editing /etc/lshell.conf directly would be overwritten on the next update.
Use per-field revert. Each editable field can be reset to the value QuickBox ships without touching your other overrides. Editing a value back to exactly the base is treated the same way — the override is dropped. Clearing all overrides resets the whole policy to the shipped base.
No. Users who are currently connected keep the previous policy for the rest of their session. The new policy takes effect for each limited user the next time they log in.
The policy editor is a dashboard surface. On the CLI you can assign a user's shell level with qb user shell -o sudo|full|limited -u <username>, and you can hand-edit /etc/lshell.conf on the server — but hand-edits are overwritten on the next qb update unless they are captured as dashboard overrides. For durable policy changes, use the editor.

Join the Community

Media server operators sharing configs, getting support, and shaping the future of QuickBox Pro.

Dedicated Support
Feature Previews
Community Configs
Active Discussions
Join Discord Server
Last updated on