Most AI agent breakouts are not zero-days. They are file permissions, sudo rules, and mounts that were too generous.
Least privilege means: the agent gets the exact files, commands, and network it needs, nothing else, for the shortest time possible. Here is how to apply that on Linux.
Quick Answer: What Does Least Privilege Mean for an AI Agent?
Give the agent its own Linux user with no sudo, ownership of exactly one work directory, and read-only mounts everywhere else. Allow at most one named privileged command via sudoers, drop all container capabilities, and re-check permissions every time you add a tool. If the agent can read your SSH keys or publish packages, the boundary is already wrong.
Key takeaways:
- Default deny, then allow named commands. NOPASSWD ALL is root with extra steps.
- Permissions rot with every new tool. Re-audit on every capability you grant.
- Five systemd lines (User, NoNewPrivileges, ProtectHome, PrivateTmp, ProtectSystem) confine a service agent with no container needed.
Linux users and file modes control the blast radius
Create a dedicated account and check what it can actually read:
sudo useradd -r -s /bin/false -m agent-runner
ls -l ~/.ssh/ 2>&1 | head -3
sudo -u agent-runner cat ~/.ssh/id_rsa 2>&1 | head -1
sudo -u agent-runner id
The cat as agent-runner should fail with Permission denied. If it succeeds, your home directory or key permissions are too open. Fix with chmod 700 ~ and chmod 600 ~/.ssh/*, and never store keys inside the agent workspace.
Sudo rules: default deny, allow specific commands
If the agent needs one privileged command, allow only that command, not full sudo:
# /etc/sudoers.d/agent-runner - edit with visudo
agent-runner ALL=(root) NOPASSWD: /usr/bin/systemctl status *
# Verify - this should work, anything else should fail
sudo -U agent-runner -l
Avoid agent-runner ALL=(ALL) NOPASSWD: ALL. That is root with extra steps. Ubuntu documents sudo and permissions in its server security guide.
Set ownership so the agent cannot wander
Ownership is the part people skip. The agent directory should belong to the agent account, and nothing else should be writable by it:
sudo chown -R agent-runner:agent-runner /srv/agent-work
sudo chmod 750 /srv/agent-work
ls -ld /srv/agent-work
# Agent writes here, but cannot write to /srv, /etc, or your home
Check effective access with sudo -u agent-runner bash -c 'touch /srv/agent-work/test && rm /srv/agent-work/test && echo writable' and confirm the same user cannot write outside that tree. If your agent runs as a systemd service, add confinement directly in the unit:
[Service]
User=agent-runner
NoNewPrivileges=yes
ProtectHome=yes
PrivateTmp=yes
ProtectSystem=strict
ReadWritePaths=/srv/agent-work
Those five lines block privilege escalation, hide home directories, and limit writes to one path. Test the service with systemd-analyze security agent.service and fix any red findings before giving the agent real tools.
Audit the boundary before you grant anything new
Permissions are set once and forgotten while tools keep accumulating. Before granting anything, check what the agent can already reach. These three commands take a minute and usually surprise people:
# What can the agent read outside its directory?
sudo -u agent-runner find /home /root /etc -readable 2>/dev/null | head -20
# What sudo does it actually have?
sudo -U agent-runner -l
# Files anyone can write (a classic breakout helper)?
find /srv/agent-work -type f -perm -o+w 2>/dev/null
Anything in the first list that is not the work directory is a finding. Fix ownership and modes first, then grant the new tool the narrowest path that makes it work, and re-run the same three commands to confirm nothing else opened up.
Sandboxing layers that actually help
- Docker with dropped capabilities:
--cap-drop ALL --read-only --user UID:GIDplus read-only mounts. See our walkthrough in Build a Sandboxed AI Agent on Ubuntu Using Docker. - systemd confinement: if you run the agent as a service, set
NoNewPrivileges=yes,ProtectHome=yes, andPrivateTmp=yesin the unit file. - AppArmor / SELinux: use the default Docker AppArmor profile. Do not disable it to fix a permission error.
Separate secrets from workspaces
Agents copy whatever they can see into prompts and logs. Keep tokens out of the mounted directory. Use environment files readable only by root, or a credential proxy, and scope tokens so a leak does not give publish rights. Our Git abuse protection guide shows the same idea for GitHub tokens.
FAQ
Is running as non-root inside Docker enough? No, if you also mount the Docker socket or host root. Non-root plus no sensitive mounts is what matters.
What about capabilities? Start with none. Add back only the one capability a failing tool needs, for example --cap-add NET_BIND_SERVICE to bind a low port.
How often should I review permissions? Every time you add a tool to the agent. New tools usually ask for broader files and network than they need.
How do I find files the agent should not see? Run sudo -u agent-runner find /home /root -readable and treat every hit as a bug. Pay special attention to SSH directories, cloud credential files, and shell history.
Should I use SELinux or AppArmor profiles for agents? Keep the defaults on and write narrow exceptions instead of disabling them. The afternoon you spend on one profile beats the incident review after a breakout you could have contained.
What to read next
Pair this with How to Secure AI Agents Running on Linux for the overview and What Happens When an AI Agent Gets Root Access to see why root is different. For log monitoring, see AI-Powered Linux Security Monitor.
External resources
Related Tools
Try these companion tools on DevStackIO Tools:
- secure password generator — create strong credentials for sandboxed AI agent access.