OpenHands
OpenHands runs an application container that creates a runtime container per conversation through the Docker socket. The runtime is where the agent's shell, browser and file tools execute. This guide assigns the app one policy and the runtimes a second.
- Runs as
- App container that spawns runtime containers through /var/run/docker.sock
- Configuration
- config.toml [sandbox], SANDBOX_* environment variables
- Runtime image
- docker.all-hands.dev/all-hands-ai/runtime
- Covered here
- The Docker runtime
Configuration and reference code for OpenHands
Why
The runtime container has whatever network the daemon gives it. Assigning it a policy inventories every destination the coding agent reaches, holds the ones it has never used, and logs each decision, without changing the image.
Requirements
Two policies, openhands-app and openhands-runtime, each bound to a site. Root on the Docker host.
1. Assign the app container
docker run -it --rm --pull=always \
--dns <openhands-app primary resolver IP> --dns <openhands-app secondary resolver IP> \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:<version>-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e SANDBOX_VOLUMES=/path/to/code:/workspace:rw \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ~/.openhands:/.openhands \
-p 127.0.0.1:3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:<version>
2. Assign the runtime containers
Runtimes are created by the app through the Docker SDK. Set the daemon default, or pass dns in docker_runtime_kwargs. The daemon default also covers a runtime started with a stale config.
{
"dns": ["<openhands-runtime primary resolver IP>", "<openhands-runtime secondary resolver IP>"],
"dns-search": []
}
[sandbox]
docker_runtime_kwargs = '{"dns": ["<openhands-runtime primary resolver IP>", "<openhands-runtime secondary resolver IP>"]}'
3. Restrict DNS egress
One rule pair on the host covers the app and every runtime. Add the second site's resolvers if the two policies use different pairs.
iptables -I DOCKER-USER -p udp --dport 53 ! -d <primary resolver IP> -j DROP
iptables -I DOCKER-USER -p tcp --dport 53 ! -d <primary resolver IP> -j DROP
4. Learn, then enforce
Import the model provider template on openhands-app. On openhands-runtime, import the package registry template only if the role installs dependencies. Run Learn Only for seven days, review New Query events, approve, then set Default Action to Deny and Greywall Mode to Enforce.
Verify
Ask the agent to run the commands in a conversation, and run them with docker exec on the app container.
getent hosts first-seen-$(date +%s).example # expected: <block page address>
dig +time=2 +tries=1 @8.8.8.8 example.com # expected: connection timed out
getent hosts api.openai.com # expected: a public address
Limits
The remote runtime (OpenHands Cloud) is not covered. Connections to a raw IP are governed by the egress firewall.
Vendor documentation this page was verified against
- OpenHands: Docker runtime (September 2026)
Vendor settings change. Securd behaviour on this page (the block page answer, the per-policy baseline, the DoH base) is a property of the product and does not.
Evaluate Agent DNS with your own agent traffic
Deploy on a single policy in learning mode and review the recorded destinations with your team.