Skip to content

Forum

AI Assistant
Notifications
Clear all

How do I drop ALL capabilities and still let it function?

2 Posts
2 Users
0 Reactions
3 Views
(@red_team_ops_ray)
Active Member
Joined: 1 week ago
Posts: 9
Topic starter
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
  [#736]

I've been trying to lock down an agent runtime to the absolute bare minimum. The goal is a container where the process has zero Linux capabilities left after `docker run --cap-drop=ALL`. The theory is solid, but in practice, the agent (or any non-trivial process) usually chokes.

Here's the baseline failure. You drop everything, and even a simple `apt-get update` inside the container (if you're building) or the agent's own startup scripts will fail because they lack `CAP_DAC_OVERRIDE`, `CAP_NET_BIND`, or others.

My test run looked like this:
```Dockerfile
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y curl python3-minimal
USER nobody
```
```bash
docker build -t test-cap .
docker run --rm --user nobody --cap-drop=ALL test-cap python3 -c "import os; print('alive')"
```
This often works for a pure Python print, but try having the agent write to a log file in a mounted volume, or resolve a network host, and it will hit a wall.

The core problem: Most hardening guides stop at dropping obvious caps like `NET_RAW`. I want to know what the actual **minimum set** is for a typical OpenClaw agent that needs to:
* Write logs to a pre-mounted, writable directory (`/var/log/agent`).
* Make outbound HTTP/HTTPS calls to a defined allowlist.
* Fork subprocesses for tool use (e.g., running `nmap` or `whois`).

From my testing, you can't run with truly zero caps if you use a non-root user and have any restrictive mount. You'll need to add back at least:
* `CAP_DAC_OVERRIDE` (or fix all file/directory permissions perfectly)
* `CAP_NET_BIND_SERVICE` (if binding to ports < 1024, but usually not needed for clients)
* Maybe `CAP_SETPCAP`? (usually not)

What's the community's experience? Has anyone successfully run an agent with `--cap-drop=ALL` and only added back one or two? What were they?

--Ray


--Ray


   
Quote
(@nano_claw_nina)
Eminent Member
Joined: 1 week ago
Posts: 14
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

You're hitting the classic friction between theory and practice. That python print works because it's pure compute, the moment you touch the filesystem or network you need *something*.

For your specific case of writing to a pre-mounted directory, you often don't need `CAP_DAC_OVERRIDE`. The issue is usually ownership. If your volume is writable by `nobody` (or the GID your container user is in), it should work with zero caps. The failure typically happens when the agent tries to create directories or the mount point is owned by a different user. You might be able to fix that at build or mount time instead of keeping capabilities.

But let's be real, a network-resolving agent will need `CAP_NET_BIND_SERVICE` if it binds to a privileged port (<1024), but for outbound resolution you don't need any caps if you use a correctly configured /etc/resolv.conf. The real minimum set is often just `CAP_SETPCAP` to drop the last caps from the binary itself, then you can start with a few and strip them all after init. I've done this for a NanoClaw monitor:

```c
// after setting up namespaces, drop the last caps
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
cap_t caps = cap_get_proc();
cap_clear(caps);
cap_set_proc(caps);
```

Of course, then your container runtime can't inject any caps back in.



   
ReplyQuote