Just saw the release notes. OpenHands v0.3.0 now supports command and network allow-lists.
This is the single biggest fix they could have made. Their "default-open" model for a self-hosted agent was a joke. Running an LLM that can `apt-get install` anything or `curl` to any endpoint by default? No thanks. 🔥
Now you can lock it down. Example config snippet:
```yaml
security:
allowed_commands:
- /usr/bin/git
- /usr/bin/find
- /usr/local/bin/my-linter
allowed_network_hosts:
- api.github.com:443
- internal-repo.corp:8443
```
Key points:
* It's a start, but it's path-based. Symlink or PATH manipulation could bypass.
* No built-in seccomp or namespacing. You still need to wrap it in a container with its own profile (AppArmor/SELinux).
* Git integration is still a massive risk surface. An `allowed_command: git` is basically giving it full control over your repo. Commit signing? Force pushes? Needs more granularity.
Aider still wins on default posture—it's more restricted out of the box. But this makes OpenHands *potentially* securable if you're willing to do the hardening work yourself.
Who's actually running this in production? What's your container sandbox look like?
--Chris
--Chris
Totally agree, the default-open model was holding me back from even trying it on my homelab. That config snippet is exactly what I needed to see.
You're right about the path-based check being weak, though. I run mine in a Podman container with a locked-down volume mount for the tools it can actually call. No /usr/bin at all, just a /tools dir with specific binaries I've copied in. Adds a step, but feels safer.
The git risk is real. I'm starting with read-only tasks for now, but granular commit controls would be a killer feature. Maybe they'll get there now that the foundation's in place.
--Jenna
Love that container approach. I used a similar trick with a read-only bind mount for /usr/local/bin in my Docker setup, but I like the idea of a clean /tools dir even better.
Have you looked at running it under systemd with a restrictive service unit? Between DynamicUser, ReadOnlyPaths, and NoNewPrivileges, you can sandbox it pretty tightly on bare metal too. Still not as isolated as a container, but good for lighter setups.
Yeah, commit controls would be huge. For now I'm using git hooks on the repo side to block anything unexpected, but that's a band-aid.
selfhost or die
The systemd sandboxing approach is a good intermediate layer, but it's important to recognize where its isolation boundaries are weaker compared to a container. Specifically, the DynamicUser, ReadOnlyPaths, and NoNewPrivileges trio does nothing to mitigate side-channel leaks through shared kernel resources.
For instance, if the agent uses the `find` tool from your /usr/bin allow-list, the timing of that binary's execution and the syscalls it makes (like `stat`) are still observable from other processes on the same host via procfs or performance counters. A container with its own PID namespace and seccomp-bpf filtering for `perf_event_open` closes that particular inference channel.
Using git hooks as a band-aid is actually a solid compensating control. It moves the security boundary to the VCS layer, which is often more appropriate for commit policy anyway. The real risk is the agent using `git` to stage and exfiltrate data via a permitted network host before the hook ever gets a chance to run.
Every tool call leaves a trace.
Oh, that systemd service unit idea is a neat middle ground. I haven't tried that yet, but it sounds perfect for my old NUC where I don't always want a full container stack running.
You mention ReadOnlyPaths. Does that actually work for the whole filesystem, like making /usr/local/bin read-only, or is it just for directories you explicitly list? I'd be worried about something like /tmp or the agent's own working directory still being writeable.
And the git hooks as a band-aid... that's a clever workaround. Are you using a pre-receive hook to scan the commit messages or the diff for certain keywords?
The `/tools` dir copy is the real solution, and it highlights how the native path-based check is basically theater. You've bypassed the vendor's "security" with a one-liner shell script.
One caveat: make sure your container runtime isn't mounting `/proc/sys/fs/binfmt_misc` or similar by default. If the agent can write there, it could potentially register a new binary format and execute code you didn't copy into `/tools`. Most default podman/docker setups are okay, but it's the kind of obscure vector these half-baked features ignore.
> granular commit controls would be a killer feature
They'll market it as that. But without a verifiable chain of trust back to the policy decision, it's just more config to get wrong. How do you *know* the commit the agent made was authorized by the current allow-list, and not by a stray prompt from three tasks ago that polluted its context? They never answer that.
> Aider still wins on default posture
That's the only comparison that matters. Default-open is a liability calculation, not a feature list.
If your first step after install is to build a container sandbox and copy binaries into a custom directory, you haven't implemented their security feature. You've worked around a fundamental design flaw.
Who's running it in production? Teams with a dedicated platform engineer to build the guardrails OpenHands should ship with. That's a cost, not a feature.
Show me the residual risk.