Restricting AI Agents When No Human Is Watching
Useful AI agents often combine three capabilities that become dangerous together: access to private data, exposure to untrusted content, and the ability to communicate with external systems. When all three exist in the same agent, prompt injection or off-script behavior can turn a bad decision into data exfiltration or a dangerous action.
The risk exists whether somebody is sitting behind the agent or not. A coding agent with a developer at the keyboard can still fetch and read malicious instructions from an external bug report, access private repositories, and communicate externally. Having a human present does not remove the risk.
Running the same agent unattended makes it harder to contain. There is nobody to reject an unexpected tool call, notice that the agent takes a strange turn, or stop the session before it continues.
This combination of private data, untrusted content, and external communication was first described as the lethal trifecta. It is a useful agentic risk model because it focuses on agentic capabilities that make a bad outcome possible, rather than assuming we can always recognize a malicious instruction or unsafe decision before the agent acts.
We ran into exactly this problem on our own infrastructure. Our engineers use background agents inside cloud development containers to investigate production issues, inspect logs and data, modify code, run tests, and open pull requests, often without anyone actively supervising the session. This might sound reckless, but software factories are rapidly becoming the new reality...
The threat model was familiar. What changed was the absence of a human as the last line of defense. When nobody is watching, the safe path has to be enforced by the system itself.
Our case
A background engineering agent investigating a production issue needs access to private data. It also processes content we do not fully control, including source code, issue comments, dependencies, tool output, logs, and information retrieved from external systems.
It also needs network access. A useful coding agent has to communicate with GitHub, internal services, package registries, and other systems to finish its work. Simply cutting off the network would make the agent safe by making it somewhat useless. All three parts of the lethal trifecta are therefore present.
The obvious alternatives were not satisfying. We could put production credentials inside the container and trust the agent to use them correctly, or require a human whenever production access was needed. The first expands the agent's authority and puts high-value credentials into the same environment as the model, shell, tools, and untrusted content. The second defeats much of the point of running the agent unattended.
We ended up with three layers. The first keeps production credentials out of the agent. The second controls behavior that never passes through the gateway. The third breaks the trifecta once sensitive data has been accessed.
Layer 1: Give the agent access, not production credentials
The first layer follows the principle from part one: give agents access to the actions they need, not the credentials behind them. We previously wrote about 'stop giving AI agents access to credentials'.
Production systems are exposed through our MCP/API gateway as controlled tools. Database credentials, logging credentials, and other production secrets stay behind the gateway, while the container has an identity that lets it request approved operations.
If the agent needs to query a production database, it requests the operation through the gateway. The gateway can enforce that the call is read-only and inspect the arguments before forwarding it. The same applies to logs and other internal systems.
This means the permissions of a broad credential do not automatically become the permissions of the agent. The database account behind the gateway may technically support writes, while the tool exposed to the agent supports only approved reads.
It also means there is no production credential inside the container for prompt injection or off-script behavior to expose. The agent can be instructed to print the password as many times as it wants. But the password is not there.
This reduces the authority available inside the agent environment, but it does not solve the whole problem. The agent still receives sensitive data, and the gateway only controls calls that actually pass through it.
Layer 2: Watch what the gateway cannot see
An agent does much more than call MCP tools or APIs. It reads and writes files, executes shell commands, invokes local tools, and can discover other ways to communicate.
The gateway sees none of that, so the agent also reports to our runtime engine. Tool calls can be evaluated before execution, giving us visibility and enforcement over actions that never reach the MCP/API gateway.
The distinction matters. The gateway governs access to the systems behind it. While agentic workflow interception provides a control point over what the agent is trying to do inside its own execution environment.
Containers give us another useful property. The hooks configuration is baked into the image and the workload runs unprivileged, so the agent cannot simply rewrite its configuration and disable the instrumentation watching it. But the agent still has private data, untrusted content, and external communication. That is where the third layer matters.
Layer 3: Break the trifecta - agentic security by design
We added a one-way egress restriction to the session. Once the agent accesses a source that was marked or automatically detected as sensitive, the session becomes restricted.
Before touching sensitive data, the agent operates within its normal network policy. After it touches a sensitive source, egress is locked down for the rest of that session.
The agent can keep working. It can reason over production data, edit files, run tests, use approved production tools, push code to its approved repository, and open a pull request. What changes is where information can leave the session.
A restricted session can communicate only with destinations approved in advance for that workflow. It cannot suddenly call an arbitrary website, use a newly discovered remote tool, or send data to an unknown endpoint because something in its context instructed it to.
The important part is that we do not need to determine whether the agent has been compromised. We do not need to classify a prompt injection or decide whether its current behavior looks malicious. The rule is deterministic: this session accessed sensitive data, so from now on it's restricted - it can communicate only with destinations approved for that workflow.
Runtime detection and protection still matters, and we use it. But the restriction does not depend on detection being right. For this particular risk, we can remove one of the capabilities required for the bad outcome instead of trying to recognize every possible way the agent might reach it, because it's hard to get it right with a very low false-positive rate. We do not try to detect the bad session. We remove the path it would need to take the data somewhere it should not go - hence getting security by design.
Making the restriction practical
Our first version of the idea sounded simple: once the agent touches production, remove network access. That also removes much of the reason for having the agent.
A background coding agent may still need to push a branch, open a pull request, report the result of a job, or call another approved internal service. All of those are technically egress. The useful rule is therefore not "nothing leaves." It is "nothing leaves through a destination we did not approve in advance."
The same principle applies to deciding what activates the restriction. We could try to infer whether every database, API, bucket, log source, or tool contains sensitive information, but that turns into another classification problem. In our case, the administrator already knows which sources are sensitive, so they declare them. Accessing one changes the state of the session.
Conclusion
Any team running unattended or (mostly) autonomous agents eventually has to answer three questions:
1. Can the agent reach sensitive systems without holding the credentials behind them?
2. What controls the actions that happen outside those governed calls?
3. And once the agent has accessed sensitive data, where is it still allowed to communicate?
For us, those answers became the MCP/API gateway, runtime enforcement, and a one-way egress restriction that locks down communication after sensitive access.
The risk model is the same whether somebody is watching or not. What unattended execution removes is the person who might catch the problem before the architecture does.
When there is nobody to approve, notice, or stop what happens next, security by design is the right way to enable this.
Related posts
The Agentic Ecosystems Is Booming
From this article, you learn how the explosive growth of AI agents, MCP servers, plugins, and skills is creating an entirely new cybersecurity challenge for enterprises. It explains why MCP adoption is accelerating across organizations, why traditional endpoint security tools are no longer enough, and how risks such as malicious open-source packages, exposed API keys, and prompt injection attacks are expanding the enterprise attack surface. The article also introduces Autonomous Security, a new enterprise tool that provides visibility, guardrails, and real-time protection for AI agents without slowing productivity, helping organizations securely scale AI adoption while maintaining governance and control.
Read MoreMCPTotal's Security Overview
Learn how we built our MCP servers hosting capability on AWS with security by design in detail.
Read MoreMCP Enters a Chinese Restaurant
Let's explore what MCP is all about, uncover the unique features that make it a groundbreaking protocol, and examine the real security risks that cannot be ignored.
Read More