Build a Basic AI Agent From Scratch: Security III
Previous parts of Build a Basic AI Agent From Scratch:
You can find and clone this code in this blog series' Github repo.
In the previous part we started closing the gaps left open by human-in-the-loop: a Docker sandbox to contain runaway commands, prompt-injection defenses so the model stops trusting tool output as instructions, and schema validation so malformed tool calls never reach execution. In this part we finish the job. We will harden the tool policy gate with path scoping, a shell denylist, and an SSRF guard, enforce resource and cost limits so a stuck loop cannot run forever, scrub secrets out of the container environment, and add audit logging and a kill switch so every decision is recorded and any session can be aborted mid-flight.
Tool Policy Hardening
In the Human in the Loop & Security part, check_permission was a single function: read tools and planning tools were always allowed, write tools were allowed inside the working directory in acceptEdits, everything else asked. That was a mode-based decision.
We now add a policy gate that runs before the mode decision. The gate has three layers:
- Path scoping: every path argument is resolved (handling relative paths, symlinks, and
..traversal) and rejected if it escapes the project working directory. This stops the agent from touching~/.ssh/id_rsa,/etc/passwd, or anything outside the project tree. - Shell policy: every
run_bashcommand is screened against a regex denylist of dangerous patterns (fork bombs,dd,mkfs, redirects into/etc/, ...) and a token-level denylist of binaries the agent should never invoke (sudo,nc,curl,chmod,docker, ...). This catches destructive and exfiltration commands. - SSRF guard: Server-Side Request Forgery is an attack where a server-side process is tricked into making requests to internal resources it shouldn't be able to reach. In an agent context, a prompt injection could make
webfetchhit…