Build a Basic AI Agent from Scratch: Security II

ruxudev1 pts0 comments

Build a Basic AI Agent From Scratch: Security II

21 Jul 2026<br>Build a Basic AI Agent From Scratch: Security II

49 minute read<br>Artificial Intelligence

Previous parts of Build a Basic AI Agent From Scratch:

Basic Agent

Tools

Long Task Planning

Human in the Loop & Security

You can find and clone this code in this blog series' Github repo.

In the previous part we gave our agent a basic safety model: permission modes, an acceptEdits trust boundary, and an ask_question tool so the agent could stop and clarify before doing something risky. That was enough to keep the agent from running wild on your machine, but it was only the first layer of defense.

These measures ultimately put the burden of security on the human instead of the machine, since the machine cannot be trusted. In many cases, this won't be enough. A human can be wrong, or they can glance over security issues because they are tired, or simply don't care. Once a tool call is approved by the human, the agent is free to run around and do all the damage its host allows it to do.

In this part we will start closing the security gaps we still have in our agent harness. We will move tool execution into a Docker sandbox so a runaway command can only touch the project directory, add prompt-injection defenses so the model stops trusting tool output as instructions, and validate every tool input against its schema before it runs.

The Security Checklist

Before writing code, it helps to lay out everything a production-grade agent harness should defend against. The codebase ships a small checklist that captures the threat model in six sections:

Prompt Injection Defense: delimit context, treat external data as data, re-validate intent

Tool Permission Gating: least privilege, destructive-action confirmation, scoped params

Input/Output Validation: validate input against schema, sanitize outputs

Loop & Resource Controls: iteration caps, token budget, timeouts, cost circuit breakers

Secret & Credential Management: no secrets in prompts, harness-level injection, per-session rotation

Observability & Kill Switches: structured decision logs, human checkpoints, session-level abort

The previous part covered the user-facing slice of (2): permission modes and clarification. This part and the next cover the rest. Each control lands in its own module in the agent source code so the rules are easy to audit and extend:

prompt_safety.py: Delimiters, trust-boundaries prompt, external-data wrapping, intent drift check.

tool_policy.py: Path scoping, shell denylist, SSRF guard, always-confirm patterns.

tools/validators.py: Dependency-free JSON-Schema validation + bounded output scope.

resource_limits.py: Iteration caps, context trimming, cost tracker.

secret_management.py: Env scan, system-prompt audit, container env scrub, session tokens.

session_control.py: Abort controller, in-flight kill, file rollback.

tools/audit.py: Append-only JSONL audit of every decision step.

tools/sandbox.py: Docker container for action tools, per-call timeout, env injection.

agent.py: Orchestration: wires every control into the agent loop.

Sandbox: Execution Security

The goal of sandboxing is to isolate the agent from the host machine. Instead of having access to everything the host machine has to offer, we build a sandbox for the agent with just the files, programs and environment variables that it needs and nothing more. Ultimately, sandboxing limits the blast radius if something bad does get executed.

Even with perfect prompt-injection defense and tool gating, you still want sandboxing because the model might find a novel exploit path you didn't anticipate, a tool implementation might have its own vulnerability, and a supply-chain attack on a tool dependency can land before you notice.

Is Docker Secure Enough as a Sandbox?

Many of you will probably point out that Docker is not actually a sandbox and that it's not secure enough for this. That is a very valid point, Docker was not built for isolation with security in mind. Docker Sandboxes (link) also exist, but this is a new feature that we won't get into yet.

So, what does Docker actually give us? It gives us filesystem isolation (the container has its own root), process isolation (processes inside can't see host PIDs), network namespacing (you can firewall egress), and resource limits (cgroups for CPU/memory caps).

What Docker doesn't give us: kernel isolation (a kernel exploit gives the attacker host root), syscall filtering by default (without a seccomp profile the container can make most Linux syscalls), protection against a privileged container (docker run --privileged is essentially host root), and GPU isolation.

If your agent is running untrusted code (e.g. a code-execution tool where the model generates arbitrary Python or bash), Docker is a weak boundary. For that workload you want stronger sandboxes like gVisor (which interposes on syscalls in user space), Firecracker MicroVMs (real hardware-virtualized VMs...

agent security tool docker basic from

Related Articles