Secure development and execution environment for AI agents with isolated networking.
AI agents need network access to be usefulβfetching documentation, calling APIs, installing packages. But unrestricted access creates serious risks:
- Data exfiltration: Agent sends proprietary code or leaks secrets (credential theft) to unauthorized endpoints. Example: Google's Gemini exfiltrating data via markdown image rendering
- Supply chain attacks: Agent installs malicious packages, compromised plugins, or executes untrusted code. Example: Hundreds of malicious MCP skills discovered in ClawHub
- Runaway costs: Agent makes unlimited API calls, racking up unexpected bills
- Lateral movement: Compromised agent pivots to internal services
The core tension: agents need enough access to work, but not so much that a misaligned or compromised agent can cause damage.
Cagent assumes the AI agent is untrusted by default. The agent may be:
| Threat | Description |
|---|---|
| Misaligned | Pursues goals that don't match user intent (prompt injection, jailbreak) |
| Compromised | Executes malicious code from a poisoned dependency or hostile input |
| Overly capable | Has access to credentials/APIs it shouldn't, even if behaving correctly |
| Unpredictable | Makes unexpected network requests due to hallucination or bugs |
| Principle | Description |
|---|---|
| Network Isolation | Cell can only reach proxy (Envoy or mitmproxy) and CoreDNS (DNS filter) - no direct internet access |
| Credential Hiding | Cell never sees API keys; credentials injected by proxy at egress |
| Defense in Depth | Multiple layers: network, container, optional kernel (gVisor) isolation |
| Least Privilege | Minimal capabilities, read-only filesystem, resource limits |
| Audit Everything | All HTTP requests, DNS queries, and syscalls logged |
| Control | Implementation |
|---|---|
| No privilege escalation | no-new-privileges security option |
| Seccomp profile | Blocks raw sockets (prevents packet-crafting bypass) |
| Resource limits | CPU, memory, PID limits enforced |
| Forced proxy | HTTP_PROXY/HTTPS_PROXY environment variables |
| Forced DNS | Container DNS set to CoreDNS filter IP |
| Control | Implementation |
|---|---|
| Internal network | cell-net marked as internal: true (no default gateway) |
| Protocol restriction | Cell can ONLY reach Envoy (HTTP), mitmproxy (HTTPS), and CoreDNS (DNS) |
| IPv6 disabled | Prevents bypass of IPv4 egress controls |
| Allowlist enforcement | CoreDNS blocks resolution of non-allowed domains |
| Egress proxy | All HTTP routed through Envoy; HTTPS through mitmproxy β Envoy |
| Raw socket blocked | Seccomp profile prevents packet crafting |
Protocol Smuggling Prevention: Raw TCP/UDP to external hosts is impossible. The cell can only reach a few IPs on the internal network: Envoy (port 8443, HTTP), mitmproxy (port 8080, HTTPS), and CoreDNS (port 53, DNS). Seccomp blocks raw socket creation (AF_PACKET), preventing packet crafting.
Residual Exfiltration Channels: Small amounts of data could theoretically be exfiltrated via DNS queries or HTTPS traffic to allowlisted domains. Mitigations: DNS tunneling detection (blocks long subdomains) and audit logging.
Defense in Depth: Network isolation doesn't depend solely on Envoy/CoreDNS being healthy. The internal: true network flag removes the default gateway at the Docker level.
The standard profile uses gVisor to intercept syscalls in user-space. This is the recommended default for production.
| Control | Implementation |
|---|---|
| gVisor runtime | runsc - syscalls never reach host kernel |
| Control | Implementation |
|---|---|
| Injection at proxy | Envoy ext_authz filter injects credentials at egress |
| Short-lived cache | Credentials cached for 5 minutes |
Run with local configuration - ideal for local use of one cell.
Lightweight setup with just 3 containers. Edit cagent.yaml and run the config generator, or edit raw coredns/Corefile and envoy/envoy.yaml directly for advanced use. Ideal for simple static domain policies on one cell.
Limitation: Credential injection is not available in minimal mode. It requires warden (add
--profile adminor--profile managed). Without warden, Envoy's ext_authz fails open β requests pass through but credentials defined incagent.yamlare not injected.
graph TD
subgraph cellnet["cell-net (isolated)"]
Cell["π Cell<br/>Isolated network Β· no direct internet<br/>All HTTP(S) via proxy Β· DNS via filter"]
HP["HTTP(S) Proxy"]
DNS["DNS Filter"]
Cell --> HP
Cell --> DNS
end
# Recommended: with gVisor (requires installation: https://gvisor.dev/docs/user_guide/install/)
docker compose --profile standard up -d
# Development: without gVisor (if not installed)
docker compose --profile dev up -dAdds warden (watches cagent.yaml) and local admin UI for browser-based management and observability. Ideal for complex and changing domain policies on one cell.
graph TD
subgraph dp["DATA PLANE"]
Warden["π‘οΈ Warden (:8081)<br/>Admin UI Β· config editor Β· terminal Β· logs<br/>Watches cagent.yaml Β· regenerates configs"]
subgraph cellnet["cell-net (isolated)"]
Cell["π Cell"]
HP["HTTP(S) Proxy<br/>egress controls"]
DNS["DNS Filter<br/>allowlist"]
Cell --> HP
Cell --> DNS
end
Warden --> cellnet
end
# Recommended: with gVisor (requires installation)
docker compose --profile standard --profile admin up -d
# Development: without gVisor
docker compose --profile dev --profile admin up -dAdmin UI (http://localhost:8081):
- Structured config editor (domains, rate limits, credentials)
- Container status with health checks
- Log viewer with traffic analytics
- Browser-based web terminal
Adds log collection and a local log store for standalone deployments. Vector collects logs from all containers and ships them to OpenObserve (local log analytics) and local files. The warden queries OpenObserve for the traffic analytics dashboard. Configure additional sinks (S3, Elasticsearch) in configs/vector/sinks/standalone.yaml.
graph TD
subgraph dp["DATA PLANE"]
Warden["π‘οΈ Warden (:8081)<br/>Admin UI Β· config sync"]
Vector["π Log Shipper (Vector)<br/>also writes to file"]
OO["π Log Store (OpenObserve)<br/>30d retention"]
Vector --> OO
Warden -- "queries" --> OO
subgraph cellnet["cell-net (isolated)"]
Cell["π Cell"]
HP["HTTP(S) Proxy<br/>egress controls"]
DNS["DNS Filter<br/>allowlist"]
Email["π§ Email Proxy β beta<br/>IMAP/SMTP Β· per-recipient policy"]
Cell --> HP
Cell --> DNS
Cell --> Email
end
Warden --> cellnet
style Email stroke-dasharray: 5 5
end
# With auditing (log collection + local log store)
docker compose --profile dev --profile admin --profile auditing up -d
# With email proxy (beta)
docker compose --profile dev --profile admin --profile auditing --profile email up -dRun multiple isolated cells on the same data plane. Each cell gets its own container with independent network isolation, sharing the same proxy, DNS filter, and policy configuration.
# 3 cells with admin UI and auditing
docker compose --profile dev --profile admin --profile auditing up -d --scale cell-dev=3Cells are named cagent-cell-dev-1, cagent-cell-dev-2, etc. All share the same cell-net network and are subject to the same domain allowlist, rate limits, and credential injection policies.
Accessing the Cell
| Method | How |
|---|---|
| Web Terminal | http://localhost:8081 (admin UI) |
| Docker exec | docker exec -it cell bash |
| SSH | Direct SSH to port 2222 (configure via admin UI) |
For centralized management of multiple data planes, connect to a control plane. Connected mode adds:
- Centralized policy management β domain policies, security profiles, and credentials managed from a single admin UI
- Multi-tenant isolation β multiple teams share one control plane with full tenant isolation
- Remote cell management β start, stop, restart, and wipe cells from the control plane
- Centralized log querying β the control plane queries each DP's local OpenObserve via warden for traffic analytics
- OAuth authentication β GitHub/Google login, API tokens, and IP ACL enforcement
graph TD
subgraph cp["CONTROL PLANE"]
UI["Admin UI"] --- API["API"] --- DB["Postgres"]
end
subgraph dp["DATA PLANE"]
Warden["π‘οΈ Warden<br/>config sync Β· heartbeat"]
Vector["π Log Shipper (Vector)<br/>also writes to file"]
OO["π Log Store (OpenObserve)<br/>30d retention"]
Vector --> OO
Warden -- "queries" --> OO
subgraph cellnet["cell-net (isolated)"]
Cell["π Cell"]
HP["HTTP(S) Proxy<br/>egress controls"]
DNS["DNS Filter<br/>allowlist"]
Cell --> HP
Cell --> DNS
end
Warden --> cellnet
end
Warden -- "heartbeat / config sync / alerts<br/>(outbound)" --> API
API -- "log queries / commands / config pushes<br/>(inbound via mTLS)" --> Warden
All connections from DP to CP are outbound β no inbound ports needed on the data plane. Log queries from the CP to warden use mTLS.
# Connected mode
CONTROL_PLANE_URL=https://api.example.com CONTROL_PLANE_TOKEN=your-agent-token \
docker compose --profile dev --profile managed --profile auditing up -d| Feature | Description |
|---|---|
| Domain Allowlist | Only approved domains can be accessed (enforced by CoreDNS and Envoy) |
| HTTPS Interception | HTTP(S) proxy decrypts HTTPS so all controls apply to encrypted traffic |
| Credential Injection | API keys injected by proxy, never exposed to cell (works for both HTTP and HTTPS) |
| Rate Limiting | Per-domain rate limits to control API usage |
| Traffic Analytics | Requests/sec, top domains, error rates in log viewer |
| Web Terminal | Browser-based shell access to cells (xterm.js) |
| gVisor Isolation | Optional kernel-level syscall isolation for defense in depth |
| Data Loss Prevention | Detects secrets, API keys, and PII in egress request bodies (log, block, or redact) |
| Email Proxy | Controlled IMAP/SMTP access with per-recipient policies - beta |
See docs/configuration.md for detailed configuration including:
- Domain policies (allowlist, path filtering, rate limits, egress limits, credentials)
- Cell management commands
- Per-cell configuration (cell-specific domain policies)
- Configuration Guide - Domains, rate limits, credentials, path filtering
- Improved secret management in standalone mode (encrypted local storage)
- Alert rules for security events (gVisor syscall denials, rate limit hits)
- Per-path rate limits and credential injection (path-level policies within a domain)
- Prompt injection protection (detect and block injected instructions in agent inputs/outputs)
MIT