Skip to content

Blog

How to limit what an AI agent can reach

You limit what an AI agent can reach by controlling four separate boundaries: the network it can call, the tools and connectors it can invoke, the knowledge it can retrieve, and what gets written down after the fact. Each is a different mechanism with its own failure mode, and treating any one of them as covering the others is where deployments get exposed.

What decides whether an agent can reach the network?

Whether an agent can reach the network at all is decided by its toolset, not by a policy layered on top of it. If an agent's toolset contains no web-browsing or web-search tool, it cannot fetch an arbitrary URL, no matter what the user asks it to do or what a prompt injection buried in a retrieved document tries to talk it into. There is no capability to call. That is the strongest version of this boundary, because it is architectural: correct once, at design time, rather than correct every time a request passes through a filter.

Most systems don't build it that way. The common pattern is to give the agent a browsing tool and then constrain what it can reach with it: egress allowlisting at the network layer, a firewall rule restricting outbound traffic to specific domains, or a forward proxy that inspects and blocks requests before they leave. These work, and they're the right choice when an agent genuinely needs to browse. But they are a filter sitting in front of a capability that still exists, and every filter has to be right on every single request. Miss one domain from the allowlist, misconfigure one proxy rule, and the gap is there until someone finds it.

Here is the part most writing on this gets wrong. An agent with zero browsing or search capability can still make outbound network calls, through its connectors. A Slack integration posting a message is a network call. A Jira ticket creation is a network call. A webhook firing into a CRM is a network call. Each one goes out over HTTPS to a fixed, known endpoint, authenticated with a token scoped to that one service. So "no internet access" is the wrong way to describe what's actually happening, because the agent isn't disconnected from the network. What's been engineered is scope: a fixed, enumerable set of destinations it can reach, versus the open set the word "internet" implies. A security review that asks "can this agent reach the internet" and accepts "no" without checking what its connectors can do has not actually established the boundary.

One example of the architectural version: Commt ships with no web-browsing and no web-search tool on the platform, for any agent, on any plan. That's a property of the toolset, not a setting a customer could turn back on by mistake.

Which tools should an agent be allowed to call?

Which tools an agent can call should run on an explicit allowlist, not a denylist, because a denylist has to anticipate every tool it hasn't seen yet. A denylist says "block these specific connectors and actions," which means the default for everything else, including whatever gets added next month, is allow. An allowlist says "these tools, and only these," which fails safe: a new integration sits unusable until someone deliberately grants it to a specific agent. The cost is real. Allowlisting adds friction to trying a new tool, and every new capability needs a deliberate decision before anyone can use it. That friction is the point, not a bug to route around.

Tool-call scoping has to check more than "is this tool switched on." At minimum it needs three things. First, the tool itself: is Slack even in scope for this agent. Second, the resource inside that tool: which channel, which Jira project, which Drive folder, because a grant to "Slack" with no resource scope is a blank check across the whole workspace. Third, the action: read or write, since a connector that's read-only for one agent might be read-write for another with a different job. And it has to check at call time, not only when the agent was configured. A token scoped broadly at setup and never re-checked per call is a static grant wearing the shape of a per-call one.

How do you make sure an agent only knows what you gave it?

You scope retrieval to the knowledge bases you've explicitly bound to the agent, and the sentence "the agent only knows what we gave it" is easy to say and hard to keep true. It holds cleanly when there's one agent and one knowledge base: the retrieval query is a filter on a single index, and there's nothing else for it to reach. It gets harder the moment two conditions show up, and almost every real deployment eventually hits both: more than one knowledge base, and more than one project or team sharing the same retrieval infrastructure.

With multiple knowledge bases, you need an explicit grant per agent, per base: is this agent bound to base A, base B, or both, and who decided that. With multiple projects sharing a vector store or an embedding pipeline, the isolation has to be enforced at the index and the query, not assumed from something upstream in the application. A bug in a filter clause here is a silent cross-tenant read. It doesn't throw an error. It returns a plausible-looking answer built from someone else's documents, which is exactly the kind of failure that goes unnoticed until someone happens to check the sources an answer cited.

Retrieval is also optional in the first place, and that's a knowledge boundary too. An agent with no knowledge base bound to it has nothing to leak from retrieval, because there's nothing there. Not every agent needs one, and the ones that don't are simpler to reason about for exactly that reason.

What should an agent's platform keep, and for how long?

What gets kept should be a deliberate retention policy, not a byproduct of logging everything because nobody decided otherwise. This boundary covers conversation content, tool call arguments and results, and retrieved chunks: what's persisted, and for how long. The default of keeping everything, forever, maximizes what you can debug and evaluate later. It also maximizes what a breach exposes. A stolen credential or a compromised export endpoint against a full-retention system hands over months of conversation history, connector payloads and whatever knowledge base content ever got retrieved into an answer.

The other default stores no message content unless a customer has explicitly set a retention window for it, keeping only what billing and rate limits actually need. That's the shape Commt uses: no message content stored by default, retention set by the customer, and deletion means the record is actually removed or irreversibly anonymised rather than flagged as hidden.

Here's the tradeoff, stated plainly rather than hidden behind either default sounding obviously correct. You cannot debug why an agent did the wrong thing, and you cannot evaluate whether its output quality is drifting, without the conversations that would show you. A minimal-retention default is a real security improvement and a real operational cost at the same time. The honest way to hold that tradeoff is to pair a low default with an opt-in debug or evaluation mode a customer can turn on for the traffic they actually want visibility into, not to pretend the cost isn't there. And if "delete" is a promise you're making, it needs to mean something specific: removed from primary storage, from search indexes, from the vector store, not a status flag that a support query can quietly ignore. Backups on a rotation are a separate, and usually acceptable, exception, but only if you say so.

How do the four boundaries work together?

They don't substitute for each other, so each has to be checked on its own terms rather than assumed from the others. A network boundary that blocks browsing says nothing about what a connector can do once it's granted. A tool allowlist says nothing about which knowledge base an agent can search. Binding an agent to the right knowledge base says nothing about how long its conversations sit in storage afterward. An agent's actual reach is the intersection of all four, not whichever one happened to get the security review's attention, and a gap in any single one is a gap in the whole thing.