I’ve been running Aider in a locked-down container for a few weeks, and my baseline policy is to block **all** outbound network from the agent’s runtime environment. My reasoning is that a coding agent with full git and filesystem access presents a significant attack surface, and its core function—code generation and editing—doesn’t inherently require external calls.
Yet, I see most community deployments allowing the agent to reach the internet for LLM APIs and, in some cases, package managers. This seems to conflate the *orchestrator’s* need for API access with the *agent’s* runtime needs.
My container setup uses a seccomp-bpf filter and drops all capabilities, but the network namespace is the most straightforward layer:
```docker
# docker-compose snippet for the agent service
network_mode: "none"
```
Or via `docker run`:
```bash
docker run --network=none ...
```
The orchestrator (which handles the LLM API calls) runs in a separate, tightly controlled service with explicit egress rules.
The risks I’m mitigating:
- Exfiltration of code or secrets via hidden git commands or file reads.
- Execution of arbitrary scripts that fetch and run payloads.
- Unauthorized use of package managers (`pip`, `npm`, `cargo`) to introduce malicious dependencies.
However, this does break some advertised features:
- Aider’s web search tool.
- Automatic dependency installation (e.g., for linting).
- Direct LLM API calls if not architected through a separate service.
My question to the forum: is this level of isolation excessive? The trade-off is functionality versus a reduced blast radius. Given the agent’s ability to execute arbitrary shell commands (even if sandboxed), I consider outbound network a high-risk vector. But perhaps I’m crippling the tool’s utility for a threat model that’s overly paranoid.
What’s your baseline network policy for self-hosted coding agents?
julia
unsafe is a four-letter word.
You're not paranoid at all, that's a solid architectural separation. The confusion you're seeing comes from people treating the agent container as a monolithic application container rather than a process boundary in a larger system.
Your point about conflating the orchestrator's needs with the agent's runtime is spot on. One caveat I'd add from experience: you need to be extremely careful about any file or code the agent can write that your *orchestrator* might later execute or interpret. A poisoned Python file the agent writes locally could trigger a subprocess that escapes the network namespace if the orchestrator isn't equally locked down.
The seccomp-bpf and dropped caps are good, but also consider mounting /proc and /sys as read-only inside the agent container if you haven't already. It prevents some sneaky information leaks.
hardened by default
Oh wow, this is actually a huge lightbulb moment for me. I've been following tutorials that just slap the API key into the agent container's environment and let it call out, and I never even considered splitting it up like this. The idea of having the agent totally offline and letting something else handle the LLM calls makes so much sense now that you say it.
But I have a maybe dumb question. If the agent can't talk to the internet, how does it know what code to write or change? Does your orchestrator just pass the LLM's response text into the container as a kind of instruction? I'm trying to picture the data flow and I'm a bit stuck on that part.
Also, thanks for mentioning the git risk specifically. That's something I definitely wouldn't have thought about on my own.
Learning every day.
That's actually the right question to ask, and you're picturing it correctly. The orchestrator becomes a dumb pipe. It takes the user's request, adds context like the current codebase, sends it to the LLM API, then feeds the raw text of the LLM's response (the proposed code changes or commands) into the agent container's stdin or via a shared volume. The agent's only job is to blindly execute that plan on the local filesystem and git repo.
Where this gets tricky, and where most tutorials fall apart, is error handling. The LLM's plan is often wrong or incomplete. The orchestrator needs a feedback loop: it must capture the agent's stderr/stdout (like a failed `pip install` or a linter error), ship *that* back to the LLM for a corrected plan, and pipe the new plan back in. This keeps the agent as a pure, isolated execution engine.
Your comment about the tutorials is sadly on point. They're written for ease of deployment, not security. Putting the API key in the agent container is like giving a prisoner a cellphone and then being shocked when they coordinate an escape. You've just bridged the containment layer.
Where's the paper?
Your architectural separation is precisely what policy as code aims to formalize. You've correctly identified the agent's true privilege boundary, which most deployments blithely ignore.
The conflation you observe stems from a lack of explicit, machine readable policy for the agent. If you were to encode this in Rego, you'd define a rule that the agent's effective permissions must be a subset of `{"filesystem.rw", "git.api"}`, with `{"network.egress"}` conspicuously absent. The orchestrator's policy would include `{"network.egress.api.llm"}`. This forces the design you've implemented.
One nuance your network namespace approach introduces is that the orchestrator now bears the responsibility for all policy decisions regarding the LLM's output before it's piped in. That's a non trivial policy engine itself, validating that the proposed git commands or file writes don't constitute an attempt to exploit the orchestrator's own network access. Have you considered how to codify those checks?
Deny by default. Allow by rule.
Great point about the orchestrator execution risk. That's the classic time-of-check vs time-of-use problem in a new form.
We've seen a case where an orchestrator read a Python file the agent wrote, tried to import it to parse some metadata, and that import executed a payload. The orchestrator needs to treat any agent output as pure data, never code, until it's been validated in a separate context.
Mounting /proc and /sys read-only is a solid addition. It stops the agent from snooping on host-level info like /proc/net/tcp that could hint at orchestrator services.
Stay secure, stay skeptical.