Once an agent can run code (a Python script to analyse a dataset, a command on a server), the old network perimeter stops protecting you. The code was written by a model, and you cannot treat it as trusted. A zero-trust design starts from one assumption: the model will eventually produce something buggy, unsafe or compromised, so the system must stay safe anyway.
In plain terms: Letting an agent run code on your server is like letting a stranger use your office computer. You would give them a locked guest room with no network cable, a time limit, and a visitor badge that opens nothing important.
Diagram: Under zero-trust principles you assume the model will eventually produce buggy, unsafe or compromised code. Generated code must never run on a host or production container. It runs inside a sandbox that limits what it can steal, escalate or change. See the animated version.
1. Runtime sandboxing: shrink the blast radius
Running generated code directly on a host or in a production container risks data theft, privilege escalation and damaging changes. Instead:
- Isolation. Run it in an unprivileged, ephemeral environment such as a gVisor sandbox, a Firecracker microVM or an unprivileged throwaway container. MicroVMs and gVisor give a stronger boundary than a plain container, because they do not share the host kernel directly.
- Immutable filesystem. Give it read-only access to the base system and a temporary in-memory disk that is destroyed as soon as the task ends.
- Resource throttling. Use Linux cgroups limits on CPU, memory, disk I/O and process count, so a runaway or malicious script cannot starve the machine.
Diagram: Agent-generated code runs inside layered isolation: a microVM or gVisor boundary, a read-only filesystem with a temporary in-memory disk, and kernel cgroup limits on CPU, memory and I/O. The whole environment is destroyed as soon as the task ends. See the animated version.
2. Egress and privilege minimisation
- No network by default. A sandbox should start with no network access at all. If a task needs one external API, allow that single destination and keep everything else blocked, so nothing can be sent out.
- Least privilege. Database credentials handed to an agent should be read-only, limited to non-sensitive schemas and short-lived. Administrative actions, such as schema changes, need an authenticated elevation step.
Diagram: A code-execution sandbox should have no network access by default. If a task needs an external API, allow that single destination and keep everything else, including the local network and the internet, blocked so data cannot leak out. See the animated version.
Diagram: Credentials given to an agent should be read-only, limited to non-sensitive schemas and short-lived. Administrative actions such as schema changes require an authenticated elevation step, and everything is logged. See the animated version.
Here is a practical starting point: a Python helper that runs untrusted code in a locked-down throwaway container. It assumes Docker is installed. For stronger isolation, add --runtime=runsc if you have gVisor set up, or use a microVM platform.
import subprocess, tempfile, pathlib
def run_untrusted(code: str, timeout_s: int = 10) -> str:
with tempfile.TemporaryDirectory() as d:
script = pathlib.Path(d, "task.py")
script.write_text(code)
cmd = [
"docker", "run", "--rm",
"--network", "none", # zero network access
"--read-only", # read-only root filesystem
"--tmpfs", "/tmp:size=64m", # small in-memory scratch space
"--memory", "256m", "--cpus", "0.5", # cgroup limits
"--pids-limit", "64", # no fork bombs
"--cap-drop", "ALL", # drop Linux capabilities
"--security-opt", "no-new-privileges",
"--user", "65534:65534", # unprivileged user
"-v", f"{script}:/task.py:ro",
"python:3.11-slim", "python", "/task.py",
]
try:
done = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout_s)
except subprocess.TimeoutExpired:
return "Stopped: time limit exceeded"
return (done.stdout + done.stderr)[:4000] # cap the output size too
Treat the agent's execution environment as an untrusted runtime boundary. That is what lets you give agents real capabilities without handing them the keys to the enterprise.
Coming Up Next
Day 27: Observability and tracing for agentic systems: telemetry, logs and metrics.
ZeroTrust #CyberSecurity #DevSecOps #Sandboxing #AIAgents
Originally published at https://sureshpallapothu.in/blog/day-26-zero-trust-ai, where this post includes animated diagrams.
Top comments (0)