Something old, but still relevant to know to avoid a simple privilege escalation path is shell escapes.
What are Shell Escapes?
Shell escapes are a feature of many text-based programs that let you temporarily exit the program’s interface to execute shell commands without closing the application.
The problem is that shell escapes don’t just give you access to a shell, it gives you access to a shell with the permissions and environment of the parent program, so if you’re running vim with sudo, any shell escape you trigger runs with root privileges, creating a potential privilege escalation vector.
This is not a bug, just a feature that has been around for ages but that can be dangerous if not managed.

How Shell Escapes Work
Here’s how shell escapes work:
- A user enters the
vimtext editor. - On the
viminterface, the user triggers a shell escape (e.g.,!/bin/sh) which instructsvim(the parent process) to invoke thefork()system call to create a new child process (the new shell). - This child process is an exact copy of the parent process (
vim), including its current state, execution environment and privileges:- Environment variables (PATH, HOME, USER, etc.)
- Working directory (current location in filesystem)
- Process permissions (UID/GID, supplementary groups)
- File descriptors (open files, network connections)
- Resource limits (memory, CPU, file handles)
- The child process then invokes the
execve()system call to replace itself with a shell (e.g.,/bin/sh). - The shell then starts execution with the inherited environment and permissions. So, if the parent process (e..g,
vim) was executed withsudoprivileges, the shell inherits these elevated privileges as well. - When the user exits the shell (via
exitorCtrl+D), the shell process terminates and control returns to the parent process (vim. - The parent process continues execution as if nothing happened.
Programs with Shell Escapes
Common Examples in Linux
In a regular Linux install, shell escapes can be done in:
- Text editors like vim and emacs support shell escapes. In vim, you can use
:shellto open a full interactive shell,:!commandto execute single commands, or even:read !commandand:write !commandto pipe content through shell commands. Each of these can be abused if vim is running with elevated privileges. - Pager programs like less and more have their own shell escape mechanisms. In less, the
!commandsyntax executes shell commands, thevkey opens your $EDITOR (which might itself support shell escapes), and the| commandsyntax pipes content through shell commands. - Database clients like mysql, psql, and sqlite3 often have shell escape features. Many allow you to execute system commands from within their interactive interfaces, which becomes a problem when these clients are run with elevated privileges or have access to sensitive data.
The GTFOBins Repository
The GTFOBins is a cool repository of Linux binaries that support shell escapes and similar privilege escalation techniques.
It’s a good to know resource, for example it shows that you can use less shell escapes like this. You’re now root, because less executed the shell with its privileges.
sudo less /etc/hosts
# Inside less, press ! followed by the command (syntax: !command)
!/bin/sh
sh-5.3 # New prompt
Container Escapes
Something i think of like an evolution of shell escapes are container escapes. They both involve breaking out of isolation to reach a more privileged environment. Instead of a shell breakout like vim, container escapes break out of container isolation to access the host.
Containers are common nowadays and a lot of them run AI/ML workloads, which makes them a good target for exploit, as some need privileged access to hardware resources like GPU, require socket mounts, or some dangerous kernel capabilities to work as intended.
Defending Against Shell Escapes
Going back to shell escapes… Defending against shell escapes is straight forward but important, there are many approaches to be protected.
Principle of Least Privilege
Always grant the minimum access necessary to users to accomplish tasks.
For sudo access, grant access to specific commands with specific arguments, not broad access to interactive programs. For example, in the sudoers file, grant access only to sudoedit for file editing tasks instead of granting overall sudo access to text editors. Use the NOEXEC tag to prevent command execution when it’s not necessary.
For containers, run with the minimum necessary capabilities. Drop all capabilities and add back only what’s required. Never run privileged containers, use rootless containers instead.
sudoedit
For file editing, grant sudoedit access to users instead of plain sudo:
# In /etc/sudoers - wrong:
user ALL=(ALL) /usr/bin/vim /etc/ssh/sshd_config
# Correct way:
user ALL=(ALL) sudoedit /etc/ssh/sshd_config
sudoedit creates a temporary copy of the target file owned by the user. It opens that copy in the user’s text editor running with the user’s normal privileges. When you save and exit, sudoedit copies the modified file back to the original location with root privileges.
Since the editor never runs as root, shell escapes only give you access to your own user account.
NOEXEC
In sudoers, use the NOEXEC tag for commands that need to run with elevated privileges but shouldn’t be able to execute other programs:
# Contents of /etc/sudoers
user ALL=(ALL) NOEXEC: /usr/bin/vim /etc/config
user ALL=(ALL) NOEXEC: /usr/bin/less /var/log/syslog
NOEXEC sets the LD_PRELOAD environment variable to load a library that intercepts calls to execve(). When a shell escape tries to spawn a new process, the call is blocked.
Some programs might use system calls that aren’t intercepted, and it can break programs that legitimately need to execute other commands. But for many use cases, it provides a good protection against shell escapes.
Conclusion
Shell escapes are not new, but they’re still relevant as they represent how privilege escalation can happen through everyday features. Sometimes a convenient functionality can lead to dangerous consequences.
The principle of least privilege is always a good welcome. Prevent sudo exploitation by granting access to specific commands, use sudoedit for file editing, apply NOEXEC where appropriate, and think about what users and containers actually need. Most privilege escalation attacks succeed because someone granted more access than necessary.
Related topics: