Zero Trust Network Sandboxing for Agentic AI, Enforced in the Linux Kernel

Last updated:

  • AI agents decide at runtime what to connect to. Host firewalls that filter by IP address can’t tell which container, process, or program opened a connection.
  • NetFoundry’s zLAN firewall sandboxes containerized AI agents with deny-by-default network policy enforced inside the Linux kernel through eBPF. It needs no container modifications, sidecar proxies, or Docker daemon changes.
  • Policy applies per container and per executable, so a shell or downloaded binary inside an allowed container still gets denied.
  • Two independent enforcement layers (packet and socket) fail closed if either layer or its daemon crashes.
  • Every connection attempt lands in a structured JSON audit log with the process, executable path, destination, and verdict.

Agentic AI is moving from demo to deployment. Companies are wiring AI agents into production workflows to read tickets, call APIs, write code, and integrate data.

That’s a new landscape, and our existing tooling wasn’t built for it. AI behavior is nondeterministic and unpredictable. An agent decides at runtime how to fulfill an objective, which could mean fetching arbitrary URLs, calling external APIs, or relaying data to destinations that were never part of the plan.

Standard host firewalls operate at the IP packet level, with no visibility into which container, process, or executable initiated a connection. From the firewall’s point of view, the AI agent exfiltrating your data and the legitimate sidecar next to it can look identical.

At NetFoundry, we approach this new landscape with three principles:

  1. Identity, visibility, and governance: Give agents sovereign identity, independent of the LLM and harness. Log everything the agents do, along with the identities and policies that enabled it.
  2. Control: Don’t give the agent any access. No network access, no API keys, no shared secrets, no standing permissions.
  3. Security: Make enterprise resources (even legacy apps) unreachable, unscannable, and undiscoverable to unauthorized identities. Unapproved AI, including shadow AI, can’t reach them, and attackers can’t exploit any vulnerabilities those resources have.

Our CEO Galeal Zino lays out the broader case for this model in You Can’t Control AI, So You Must Control the Network. This post focuses on the second principle, where the agent gets no access from birth, programmatically and deterministically, and on the kernel-level sandbox we built to enforce it.

What Is a Zero Trust Network Sandbox for AI Agents?

A Zero Trust network sandbox for AI agents blocks every outbound connection an agent tries to make unless policy explicitly allows it, based on the identity of the process making the request. NetFoundry’s version is a Zero Trust, identity microsegmented network sandbox for agentic AI, enforced entirely inside the Linux kernel. We built it for containerized AI systems running in plain Docker with the NetFoundry zLAN firewall running on standard Linux hosts: no container modifications, no sidecar proxies, no changes to the Docker daemon.

The sandbox delivers four business-level guarantees:

  • Deny by default, for everything: No outbound connection leaves a container unless a specific rule for that destination and port has been explicitly programmed. A brand-new container with no policy doesn’t get “temporary” open access while someone writes rules.
  • Per-container and per-executable policy: Policy can go further than “this container may reach this address.” You can say “only curl and node inside this container may reach this address.” A shell an attacker spawns, a Python subprocess, or a binary the agent downloaded and ran gets denied before a single packet exists, even when it’s running inside an allowed container.
  • Isolation that survives shared infrastructure: Modern container stacks often share network namespaces (an agent and its network sidecar seeing the same interface, for example). This model keeps their policies completely separate anyway, because enforcement keys off kernel identity, not IP addresses or interfaces.
  • A complete audit trail: Every connection attempt is logged as structured JSON with the process, executable path, destination, and verdict. When someone asks “what did the agent actually try to reach last Tuesday?”, you have the answer.

All four guarantees come from the same kernel-level mechanism.

How eBPF Enforces Deny-by-Default Network Policy for AI Agents

The mechanism behind all of this is eBPF: small, verified programs that run inside the Linux kernel itself. Two independent enforcement layers work together:

  1. Filter packets as they leave container interfaces
  2. Intercept connect() system calls at the socket layer, before a packet is ever generated, and route authorized packets on an identity microsegmented overlay.

If either layer fails or its managing daemon crashes, the system fails closed: the default remains deny, not allow. (Full technical detail on both layers is in the technical reference section below.)

What a Zero Trust Sandbox Looks Like for an OpenClaw AI Agent

Our reference deployment, OpenClaw, is a three-container agentic AI stack: the AI agent itself, a Ziti network tunnel sidecar that provides Zero Trust overlay connectivity, and an LLM inference proxy that brokers access to the actual AI backends.

The agent’s entire view of the network is six rules: a few DNS resolvers, the Ziti overlay network (and even that only for two named executables), the LLM gateway proxy, and a local tunnel port. Arbitrary internet IPs, cloud provider APIs, GitHub, Cloudflare, cloud metadata endpoints: all denied. You can watch it happen live:

[cache:MISS/DENY] cg=513770 openclaw-gateway 185.199.108.153:443 (github.com)
[cache:MISS/DENY] cg=513770 openclaw-gateway 104.18.8.70:443    (cloudflare)

Two details of this deployment show why the design matters.

How the Sandbox Separates an Agent From Its Sidecar on a Shared Interface

The agent and the tunnel sidecar share a network namespace: they see the same eth0 and present the same source IP to the network. The tunnel legitimately needs to reach Ziti controllers on the public internet. If packet filtering on the shared interface were the only enforcement, the agent could ride along and reach those same controller addresses. Instead, the socket-layer hook checks the kernel cgroup identity of the calling process (the kernel assigns the agent and the sidecar different cgroup IDs even though they share the interface), and the agent’s policy contains no entry for the controller addresses. Its connect() call fails with a permission error and no packet is ever generated. The packet layer never even sees it.

How the Sandbox Keeps LLM API Keys Out of the Agent’s Blast Radius

The agent’s only path toward AI inference is the LLM gateway proxy. The backends behind that gateway (their addresses, model endpoints, and API keys) are unreachable from the agent through any permitted path. Even a fully hijacked agent cannot enumerate or directly contact the model backends, because the credentials and routes simply don’t exist in its network world.

How to Extend AI Agent Network Policy to Host Processes

Agentic AI doesn’t only live in containers. The same socket-layer enforcement can optionally extend to host processes: binaries and systemd services running directly on the machine. Disabled, it still logs every host connection for visibility. Enabled, host processes are classified and policed with the same allow-list model, and anything unclassified is denied rather than allowed. A host-resident AI executable gets the same treatment as a containerized one.

Technical Reference: How zfw’s eBPF Enforcement Layers Work

This section covers the implementation in detail for engineers evaluating the architecture. The enforcement runs on zfw, the open-source eBPF firewall module inside zLAN.

Two Independent eBPF Enforcement Layers

Layer 1: TC CLSACT default-deny (packet level). A zfw_tc_ingress BPF program attaches to each container veth interface and to the Docker bridge. The fundamental rule: no outbound packet leaves a container veth unless a specific CIDR/port rule has been explicitly programmed. The TC layer is stateful: it tracks TCP handshake states and UDP directional flows, and drops mid-session packets that lack a matching flow entry regardless of policy. If the userspace daemon terminates, no new rules are added and existing rules remain unchanged: the default remains deny, never allow.

Layer 2: cgroup/connect4 LPM (socket level). A second BPF program (zfw_zlan_visibility.bpf) attaches to the root cgroup and intercepts every connect() syscall on the host. Its enforcement key is the kernel cgroup ID rather than the veth interface, which is exactly why containers sharing a network namespace (and therefore an interface and source IP) still receive completely separate longest-prefix-match (LPM) policies: the kernel assigns them separate cgroup IDs. In the OpenClaw stack, the agent and the tunnel sidecar share eth0 via Docker Compose’s network_mode: service:ziti-tunnel, yet carry cgroup IDs 513770 and 513684 respectively, each with its own policy table.

The userspace side splits into three processes so a crash in one layer can’t take down the other: zfw_state manages TC stateful session tracking, zfw_interface_state maintains TC interface state, and zfw_cg_state owns Docker/cgroup tracking and BPF map visibility.

How the BPF Gatekeeper Decides on Each connect() Call

For each connect() call, the BPF gatekeeper executes this sequence:

  1. Look up the calling process’s cgroup ID in cgroup_policy_map. If found, proceed to LPM lookup; if not found, check unmanaged_container_map and apply host enforcement classification if enabled.
  2. Check the LRU verdict cache (zlan_visibility_map). Cache hits return stored verdicts immediately without LPM processing, except when executable filters are active on the matching policy row.
  3. Perform the LPM lookup on zlan_policy_map, scanning all matching port ranges and computing a union of their executable masks. Deny if no range covers the destination port, or if every matching range carries an executable filter that excludes the calling process’s path.
  4. Write the verdict to the LRU cache (skipped for executable-filtered rows).
  5. Emit a JSON event to the zlan_events ring buffer containing process ID, executable path, destination IP and port, protocol, and verdict.

The Complete OpenClaw Container Policy

The openclaw container (cgroup ID 513770) is permitted exactly:

  • 127.0.0.11:53/udp: Docker embedded DNS resolver
  • 100.64.0.2:53/udp: Ziti DNS resolver
  • 172.25.0.10:53/udp: subnet DNS
  • 100.64.0.0/16:443/tcp: Ziti overlay, executable-filtered to /usr/bin/curl and /usr/local/bin/node only
  • 172.25.0.11:10000/tcp: LLM gateway proxy
  • 127.0.0.1:18789/tcp: ziti-tunnel local port

The executable allow-list on the Ziti overlay row means that any other process inside the openclaw cgroup (shells, Python subprocesses, downloaded binaries) is denied at the socket layer before packet transmission, even though the CIDR/port would otherwise match.

Why the Shared-Namespace Case Needs Both Layers

TC rules on the shared veth (veth2b61fb3) permit traffic for ziti-tunnel‘s CIDRs, including the Ziti controllers at 44.208.230.176:443 and 44.214.121.10:443. If TC were the sole enforcement mechanism, openclaw could reach those addresses, since it shares the same physical interface and source IP. The cgroup/connect4 layer closes the gap: the hook fires before packet transmission, finds no LPM entry for 44.208.x.x under cgroup 513770, and the connect() returns EPERM. No packet is generated; the TC layer never encounters it.

How Deny-by-Default Handles Unknown Containers

When a container starts with no matching policy rows, the daemon writes its cgroup ID to unmanaged_container_map along with its name and detected OS (from /etc/os-release). The gatekeeper denies all outbound connect() calls for any cgroup ID in this map, and the TC layer independently blocks all packets. Inspect the current set with:

sudo zfw -L --unmanaged-containers

Adding a policy row for a running container (zfw --docker-policy ... --insert) promotes it out of unmanaged tracking immediately, no restart required.

How Host-Service Enforcement Classifies Processes

Host enforcement is disabled by default; in that state, host process connect() calls are logged but never denied. When enabled via zfw --host-enforcement-enable, host cgroups are classified by their cgroupfs path: cgroups ending in .service map to HOST_CLASS_ALLOW (allowed unless explicit policy exists) or HOST_CLASS_RESTRICTED (consult the LPM), and all others are HOST_CLASS_RESTRICTED. A cgroup absent from host_cgroup_class_map is denied rather than allowed: host processes have no TC backing, so fail-closed is the only safe default.

What the JSON Audit Trail Captures

Every connect() call (allowed or denied, container or host) generates a JSON event:

{"namespace":"zfw.connect.events","event":"connect_allowed","container_name":"openclaw-gateway",
 "cg_id":"513770","pid":1042,"exe":"/usr/bin/curl","daddr":"198.18.1.1","dport":443,
 "timestamp_utc":1777511329}

Host process events appear with "image":"unknown" and empty veth and bridge fields, with executable path, process ID, cgroup ID, and destination captured identically. All events (container lifecycle, policy decisions, and host process activity) stream to /var/log/zfw_cgroup_events.log as newline-delimited JSON, making forensic correlation straightforward.

How to Stop AI Agents From Reaching Anything You Didn’t Authorize

AI agents are nondeterministic by design, and prompt injection means you can’t fully trust an agent’s own judgment about where it should connect. What you can trust is a kernel that refuses to create the connection in the first place. Deny-by-default, per-executable network policy, enforced below the agent, invisible to it, and impossible for it to route around, turns “we hope the agent behaves” into “the agent physically cannot misbehave on the network.”

NetFoundry was founded by the inventors and maintainers of OpenZiti, and we built our platform around this kind of control. Every AI agent, MCP server, and LLM gets its own cryptographic identity and connects only to the specific services it’s authorized for, with no open inbound ports, no VPNs, and no firewall changes. The zLAN sandbox brings that same Identity-First Reachability™ model inside the host itself.

To see the sandbox enforce policy on your own agent stack, [request a zLAN demo](CTA URL: Stephen to confirm) and our engineers will walk you through it.


Frequently Asked Questions

What is a network sandbox for AI agents?

A network sandbox for AI agents blocks every connection an agent tries to make unless a policy explicitly allows that destination. At NetFoundry, we enforce the sandbox inside the Linux kernel and tie each rule to the identity of the specific container and program asking to connect. Think of a building where every door stays locked by default and each badge opens only the rooms on its list. If an agent gets hijacked or goes off script, it still can’t reach anything outside its list.

How do you stop an AI agent from exfiltrating data?

The most reliable way to stop an AI agent from exfiltrating data is to block its outbound network access by default and allow only the specific destinations it needs. NetFoundry’s zLAN firewall enforces that deny-by-default policy in the Linux kernel, below the agent, so the agent can’t see or change the rules. Policy also applies per program, so a malicious script or downloaded tool inside the agent’s container gets denied even when the container has approved destinations. The firewall logs every attempt, so security teams can see exactly what the agent tried to reach.

Why can’t traditional firewalls secure AI agents?

Traditional host firewalls make decisions based on IP addresses and ports, so they can’t tell which container, process, or program opened a connection. NetFoundry sees this as the core gap for agentic AI. An agent exfiltrating data and a legitimate service next to it can look identical to a packet-level firewall, especially when they share a network interface and source IP. Our approach checks the kernel’s identity for the specific process behind each connection request, so two workloads that look the same to a firewall still get completely separate policies.

How do you secure AI agents with Zero Trust?

Securing AI agents with Zero Trust means giving each agent its own verifiable identity, granting it no network access by default, and authorizing only the specific resources it needs. NetFoundry builds this on three principles. Every agent gets its own identity, independent of the LLM or framework it runs on, and every action gets logged against that identity. Agents start with no network access, API keys, or standing permissions. Enterprise resources stay unreachable and undiscoverable to any identity that isn’t authorized, which also shuts out shadow AI and attackers scanning for vulnerabilities.

What is an LLM gateway, and why does Zero Trust require one?

An LLM gateway is a proxy between AI agents and the large language models they call. It brokers every inference request and holds the model credentials so agents never see them. At NetFoundry, we treat the gateway as a requirement for Zero Trust AI because it removes standing secrets from the agent. In our sandbox model, the gateway is the agent’s only path to inference, and the backends, endpoints, and API keys behind it stay unreachable. Even a fully hijacked agent can’t find or contact the models directly, because those routes and credentials don’t exist from its point of view.

Does sandboxing AI agents require changes to containers or Docker?

Kernel-level sandboxing with eBPF can enforce network policy on containers without modifying them. NetFoundry’s zLAN firewall runs on standard Linux hosts alongside plain Docker and requires no container modifications, no sidecar proxies, and no changes to the Docker daemon. The firewall blocks new containers with no policy automatically, and a policy added for a running container takes effect immediately with no restart.

Related Reading