Build a Basic AI Agent From Scratch: Security and Controls (Part III)
Wrapping up the AI Agent series by hardening tool policy gates, adding shell denylists, SSRF guards, and resource limits.

Stock photo for illustration only, not from the actual event
- Implemented a 3-layer policy gate to screen tool calls before mode decisions
- Added shell binary denylists and SSRF web protections for high-risk tools
- Enforced context budget limits using rough token estimation and trimming
- Added safety controls, audit logging, and kill switches for robust execution
Reaching the final part of our Build a Basic AI Agent from scratch series, we complete the mission of securing our agent. In previous segments, we began closing gaps left by human-in-the-loop controls by introducing a Docker sandbox to contain runaway commands, prompt-injection defenses to stop models from trusting tool outputs blindly, and schema validation. In this installment, we finalize the security hardening by introducing path scoping, shell command restrictions, server-side request forgery (SSRF) guards, resource and cost limits, environment secret scrubbing, audit logging, and a kill switch.
Previously, check_permission was a single function handling mode-based decisions where read and planning tools were always allowed, and write tools were permitted within the working directory during acceptEdits. We have now introduced a policy gate running strictly before the mode-based decision. This gate consists of three layers: path scope checking, shell policy enforcement, and web/SSRF policy validation. A failure at any of these layers results in a hard block that no permission mode can override.
Path scoping has been generalized beyond just write tools to encompass every tool utilizing paths, such as read_file, glob_files, grep, write_file, and edit_file. Each path argument is resolved—handling relative paths, symlinks, and directory traversals—and rejected outright if it escapes the designated working directory. Meanwhile, run_bash remains the most dangerous tool, receiving its own specialized screening against a regex denylist of dangerous binaries including docker, sudo, su, nc, netcat, curl, wget, chmod, and various system service controls.

Stock photo for illustration only, not from the actual event
For web policy and SSRF mitigation, the webfetch tool is screened against cloud metadata endpoints, localhost, and private IP ranges. Hosts are resolved via getaddrinfo, and each resulting IP address is evaluated using the ipaddress library to block loopback, link-local, multicast, and RFC1918 private ranges. This stops models from fetching cloud IAM credentials from metadata endpoints or probing internal services on private networks.
Adopting a multi-layered defense-in-depth architecture, such as combining strict path scoping with shell command denylists, is crucial when deploying autonomous agents. Restricting execution capabilities at the code level drastically reduces the blast radius if an agent falls victim to indirect prompt injection or unexpected execution loops.
Beyond hard policy gates, certain hazardous patterns require explicit confirmation regardless of active permission modes, such as force-pushing to git repositories or overwriting existing files with empty content. Furthermore, developers can leverage the --tools CLI flag to pass a comma-delimited allowlist, ensuring the LLM registry only exposes tools that are strictly necessary for the current task.
To prevent runaway execution loops while unsupervised, resource and cost controls have been integrated. ContextBudget tracks cumulative tokens using a heuristic of roughly 4 characters per token and trims conversation histories before each API call. The default limit is set to 24,000 tokens and can be overridden via --max-context-tokens, ensuring stuck loops are terminated quickly and efficiently.
Source: Dev.to
Found something wrong in this article? Report an issue with this article
Comments
Leave a Comment