The right way to give OpenClaw sudo access isn't NOPASSWD: ALL — that hands the bot full root and undoes most of your hardening work. The production-safe pattern is a scoped sudoers fragment that lets OpenClaw run only the specific commands it actually needs (apt, systemctl, ufw, docker), with everything else still requiring a human at the keyboard.
This post is the deep-dive companion to the full hardening guide. The pillar covers the whole hardening checklist; this one focuses on getting sudo right, which is one of the easiest places to silently undo the rest of your work. Defaults and JSON paths come from the OpenClaw docs.
Why blanket NOPASSWD: ALL is the wrong answer
NOPASSWD: ALL is the line in /etc/sudoers (or a fragment in /etc/sudoers.d/) that says: "this user can run any command via sudo without ever entering a password." It's the path of least resistance when you hit a sudo prompt that breaks an automation, and it shows up in install scripts and tutorials more often than it should.
The problem is that it makes the user functionally equivalent to root. Anything the bot can be tricked into running, it runs with full root authority — no password gate, no command allowlist, no second chance. That includes:
- Prompt injection. A web page the bot reads contains a hidden instruction. The bot decides to "investigate" by running a shell command. With
NOPASSWD: ALL, that shell command canrm -rfyour home directory, write a new SSH key for the attacker, or open a reverse shell. - Supply-chain compromise. A package OpenClaw installs is compromised upstream. The package's post-install script runs as root because sudo is wide open.
- Accidental destructive command. The bot generates a one-liner with a typo. Without sudo prompts, there's no friction stopping it.
If you've already gone through the work of running OpenClaw as a non-root user, sandboxing subagents in Docker, and locking the gateway behind Tailscale, granting NOPASSWD: ALL quietly cancels most of that effort. The blast radius of a compromise becomes "everything on the host" again.
The right mental model: sudo is a capability you hand to the bot, and you should hand it the smallest one that still gets the job done.
The mental model: scoped commands via /etc/sudoers.d/openclaw
Linux gives you a clean way to scope sudo capabilities. Instead of editing /etc/sudoers directly (which is shared with the OS package manager and easy to mangle), drop a separate file into /etc/sudoers.d/. Each file in that directory is read as if it were appended to the main sudoers config.
This pattern has three big advantages:
- Package-manager safe. Distro upgrades won't touch your fragment.
/etc/sudoersitself sometimes gets overwritten on package updates;/etc/sudoers.d/openclawdoes not. - Easy to revoke. Removing OpenClaw's sudo capabilities is one
rmcommand. - Reviewable. A short file with five lines is much easier to audit than a 200-line
/etc/sudoerswith your changes mixed in.
The syntax for a scoped rule is:
<user> <host>=(<runas>) NOPASSWD: <command1>, <command2>, ...
For an OpenClaw fragment that's almost always:
openclaw ALL=(root) NOPASSWD: /usr/bin/apt-get update, /usr/bin/apt-get install -y *
<user>: the OS user OpenClaw runs as. <host>=ALL: applies regardless of which host the rule is on (fine for single-host deployments). (root): the target user — what OpenClaw becomes when it runs the command. NOPASSWD: lets the rule bypass the password prompt only for these specific commands. Then a comma-separated list of allowed commands.
Two non-negotiables when authoring the file:
- Always validate before activating. Run
sudo visudo -cf /etc/sudoers.d/openclawto check the syntax. A broken sudoers file can lock you out of sudo entirely.visudo -cparses the file without committing it. - File permissions must be
440(chmod 440 /etc/sudoers.d/openclaw) and owner must beroot:root.sudowill refuse to read the file otherwise — a safety feature, not a bug.
The minimal sudoers fragment that covers OpenClaw's actual needs
Here's the fragment I run in production, with comments so you can adapt it to your environment:
# /etc/sudoers.d/openclaw — scoped sudo capabilities for the OpenClaw bot
# After editing: sudo visudo -cf /etc/sudoers.d/openclaw && sudo chmod 440 /etc/sudoers.d/openclaw
# Package management — apt only, no arbitrary scripts
openclaw ALL=(root) NOPASSWD: /usr/bin/apt-get update
openclaw ALL=(root) NOPASSWD: /usr/bin/apt-get install -y *
openclaw ALL=(root) NOPASSWD: /usr/bin/apt-get upgrade -y
openclaw ALL=(root) NOPASSWD: /usr/bin/apt list --upgradable
# Service control — only OpenClaw-related units
openclaw ALL=(root) NOPASSWD: /bin/systemctl restart openclaw
openclaw ALL=(root) NOPASSWD: /bin/systemctl status openclaw
openclaw ALL=(root) NOPASSWD: /bin/systemctl restart fail2ban
openclaw ALL=(root) NOPASSWD: /bin/systemctl status fail2ban
# Firewall — let the bot inspect, but require a password for changes
openclaw ALL=(root) NOPASSWD: /usr/sbin/ufw status verbose
# Note: no NOPASSWD for `ufw allow` / `ufw deny` — those still prompt
# Docker — only needed if openclaw is not in the docker group
# (preferred path: add openclaw to docker group, drop these lines)
openclaw ALL=(root) NOPASSWD: /usr/bin/docker ps
openclaw ALL=(root) NOPASSWD: /usr/bin/docker logs *
A few things worth understanding about this fragment:
- Wildcards in command lists are sharp.
/usr/bin/apt-get install -y *means "any package name." If your bot decides to install a malicious package, this rule allows it. Tighten to a specific package list (apt-get install -y htop, jq, nmap) if you can. - Absolute paths are required. Sudoers does not honor
$PATH. Always write/usr/bin/apt-get, never justapt-get. Find a binary's absolute path withwhich apt-get. - Service control is per-unit.
systemctl restart openclawis allowed;systemctl restart sshdis not. Add specific units only as needed. - Read-only commands are safer than write commands.
ufw statusis read-only and fine to allow.ufw allow 2222modifies firewall state and should still prompt. - Prefer group membership over sudo for Docker. If the user is in the
dockergroup, no sudo is needed at all fordockercommands. The sudo rules above are a fallback when group membership isn't available.
After saving the file, validate and lock it down:
sudo visudo -cf /etc/sudoers.d/openclaw
sudo chown root:root /etc/sudoers.d/openclaw
sudo chmod 440 /etc/sudoers.d/openclaw
Then test as the OpenClaw user:
sudo -u openclaw sudo -l
You'll see the list of NOPASSWD commands. If you see "user openclaw is not in the sudoers file," the fragment isn't being read — most likely a permissions or syntax issue.
Auditing what OpenClaw ran with sudo
A scoped sudoers file isn't a substitute for visibility. Sudo logs every invocation, and reviewing those logs is the only way to catch a misbehaving bot before it causes real damage.
On systems using systemd-journald (Ubuntu 16.04+, Debian 9+, Fedora, modern CentOS):
journalctl _COMM=sudo --grep " openclaw : " --since "1 hour ago"
On older systems or where /var/log/auth.log is still primary:
sudo grep " openclaw : " /var/log/auth.log | tail -50
Why the space-padded pattern: sudo's log format puts the calling user first (openclaw : TTY=... USER=root ; COMMAND=...), where USER= is actually the target user. Filtering on USER=openclaw would catch the wrong rows. Matching openclaw : (with surrounding spaces) reliably hits the calling-user position.
A typical entry looks like:
sudo: openclaw : TTY=unknown ; PWD=/home/openclaw ; USER=root ; COMMAND=/usr/bin/apt-get update
What to look for:
- Unexpected commands. Anything outside your sudoers fragment should not appear here. If it does, the fragment isn't enforcing what you think it is.
- Repeated failures. A line ending in
command not allowedmeans the bot tried something the fragment denied. One or two of these are normal during development; a sustained burst suggests the bot is confused or being prompted to escalate. - Out-of-window activity. If you only run commands during your working hours but logs show sudo invocations at 3am, that's a signal worth investigating.
For ongoing monitoring, I send a daily summary to my Telegram via the OpenClaw cron pattern from the pillar guide:
Each morning at 8am, summarize all sudo invocations by openclaw from
the last 24 hours. List any commands not in /etc/sudoers.d/openclaw,
any denied attempts, and any activity outside 8am-11pm local time.
That single rule has caught two real config drifts on my host — both benign in the end, but the visibility was the whole point.
Revoking sudo cleanly when you're done
When you decommission OpenClaw on a host, switch users, or suspect something is off, revoke sudo with three commands.
1. Remove from the sudo group:
sudo gpasswd -d openclaw sudo
This removes the user from the broad-sudo group. After this, only the rules in /etc/sudoers.d/openclaw apply.
2. Delete the scoped sudoers fragment:
sudo rm /etc/sudoers.d/openclaw
The fragment is gone — OpenClaw can no longer use any of the NOPASSWD rules.
3. Verify the revocation:
sudo -l -U openclaw
The output should be Sorry, user openclaw is not allowed to run sudo on <hostname>. If you still see rule entries, one of the previous steps didn't take — check that the fragment was actually deleted (ls /etc/sudoers.d/) and that the user isn't in any other sudo-granting group (groups openclaw).
If OpenClaw was actively running when you revoked, restart it to drop any cached sudo tokens:
sudo systemctl restart openclaw
That's the whole revocation. Three commands, fully reversible by re-adding the group membership and the fragment if you change your mind.