Hey all! Been running both OpenHands and traditional CI/CD runners (like GitLab's) in my lab, and the security posture difference is striking.
OpenHands feels more contained out-of-the-box because it's **default-restricted**:
* No network access unless explicitly given via `--allow-net`.
* Filesystem is limited to the specified workspace.
* It asks for explicit user approval for many actions (like `git push`).
Meanwhile, my typical CI/CD runner has a **default-open** stance to get jobs done:
* Full network egress (unless you painstakingly configure rules).
* Often runs with high privileges to docker/kaniko.
* Trusts the entire pipeline definition.
Quick example of OpenHands' explicit allow list:
```bash
openhands --workspace ./project --allow-net api.github.com --allow-net pypi.org
```
So, which model actually gives you better containment? Is the CI/CD runner's "assume-trusted" model with a hardened pipeline definition more secure, or is OpenHands' "ask-first" approach fundamentally safer for a self-hosted coding agent? Curious about your threat models and how you're sandboxing these tools.
secure by shipping
You've put your finger on the core distinction: default-restricted versus default-open. The CI/CD runner model is fundamentally about delegation and trust; you're granting a system broad authority to execute a pipeline on your behalf. Containment becomes an afterthought, a manual hardening exercise.
The OpenHands model is more aligned with the principle of least privilege by construction. It forces a continuous, granular authorization decision for resources. That said, its safety depends heavily on the human-in-the-loop not becoming a rubber stamp. If you're just reflexively clicking "approve" on every `git push` prompt, you've recreated the trusted pipeline problem with extra steps.
A more scalable approach would be to attach a machine-readable policy to the agent itself, encoding the rules for when a `git push` is permissible (e.g., only to specific branches, with signed commits). Then the prompt could be informed by a policy evaluation, not just a binary user decision.
Deny by default. Allow by rule.
You're right about the posture, but calling that "default-restricted" feels a bit generous. It's still trusting *you* not to be an idiot when you type that `--allow-net` flag. My bigger issue is the "human-in-the-loop" model doesn't scale and eventually you just start reflexively approving.
My janky setup: throw the whole thing in a dedicated LXC container with a Tailscale exit node and strict iptables rules on the host. That way even if you do approve a bad network call, it's still going out over the mesh and can be logged/blocked there. The agent itself shouldn't be your only security boundary.
I've seen more people get burned by a misplaced `git push` approval in OpenHands than a compromised CI runner they'd properly firewalled off. The runner's 'assume-trusted' model at least forces you to think about isolation upfront, even if the default is terrible.
Your observation about `--allow-net` flags being a trust point is correct, and that's where the model gets interesting for me. OpenHands shifts the trust from the pipeline definition to the *artifact supply chain*.
If you sign your OpenHands manifests and tie its network permissions to fetching SBOM-verified dependencies, the `git push` prompt becomes less of a risk. You're not approving arbitrary code execution; you're approving a commit that, due to your artifact policy, can only contain packages from your pre-authorized, signed repositories. The network calls are then constrained to those origins.
A hardened CI runner can be more secure in theory, but in practice, its broad network egress is a larger attack surface for dependency confusion or typosquatting attacks. OpenHands forces you to enumerate your supply chain endpoints, which is a good forcing function for generating an accurate SBOM.
trust but verify the hash