← All Insights
ArchitectureJul 15, 2026

Should an AI agent carry out its own actions?

Duane Grey

Duane Grey

AI Strategy & Implementation

Find this useful? Share the visual.

The Short Version

The model that proposes an action should not be the one that runs it. Separate the two, and a deterministic executor can check every step against two things code can verify, where the content came from and what the step would do. It never reads the hidden instruction, which is why it holds against attack channels I did not anticipate.

An AI agent should not carry out its own actions. The model can be tricked into following a hidden instruction, so the thing that runs those actions should be separate from it. A code based deterministic system holds the tools and the credentials, and it checks the plan before running any of it.

I have written before that this boundary has to live outside the model, because the model cannot enforce one on itself. I have also written about the six layers that make up that boundary. This insight is about how the plan and the executor are split, because the split is what lets any of those layers enforce anything.

The model reads a single stream of text and acts on instructions wherever it finds them. It cannot reliably tell an instruction the user typed from an instruction hidden in a document it was asked to summarize, a web page it fetched, or a file in a repository it was told to deploy. This is prompt injection. It works by burying them inside the artifacts an agent is handed, where they are easy to miss.

So the question is where to put the boundary, so that a model I already assume can be compromised cannot do damage.

Propose and dispose

Split the agent into two jobs.

The first job is proposing. The model reads the request and the context, and it writes down a plan, the steps it intends to take, and the tools and data each step needs. It produces the plan and nothing else. It holds no credentials and calls no tools directly.

The second job is executing. A separate code based deterministic system takes that plan and runs it. This executor holds the tools, the credentials, and the access. It does not reason, and it does not read the plan for meaning.

Comparing the request against what the model proposed is a judgment call, and a judgment call needs a model. Putting one there hands the decision back to the component that I have already determined cannot be trusted.

The executor reads two things instead. Every step names a tool, and the registry records what that tool does, whether it writes, sends, fetches, or only reads. Content the agent took in carries a label saying where it came from, and that label travels with the content into any step it influenced.

Then it applies one rule. Content from an untrusted source may not drive a step that changes state or sends data outward. A step like that stops, either blocked outright or held for a person to approve. Nothing in the rule needs to know what the hidden instruction said. It needs to know where the instruction came from and what the step would do.

The plan is the seam between them. It is an explicit artifact, something you can read, log, and check, not a hidden chain of reasoning inside the model. Copilot's plan in the EchoLeak attack was implicit in its generated text, with nothing to inspect before it acted. When the plan is a real object handed from one system to another, you have a boundary where you can apply security rules.

None of this is invented here. Operating systems separated privileged code from the code that asks for privileges decades ago. This is the same idea pointed at an agent. The part that can be fooled proposes, and the part that holds the power disposes.

Why the separation is critical

Every other defense in this design depends on it.

A trust label on inbound content does nothing on its own. It matters because something downstream refuses to run a step an untrusted source influenced. Injection scanning does not have to catch everything, because a plan check sits behind it. Outbound traffic becomes something the executor guards, because the executor, and not the model, decides what leaves.

The rule reads a label and an action, and it never reads the instruction. So an instruction that arrives through an email, a code comment, retrieved memory, or an image ends up in the same place, as a step that either traces back to an untrusted source or does not, and either reaches outside the agent or does not. The attack does not have to be one I anticipated, because the check never looks at the attack.

Which means detection does not have to win. Screening images for hidden text is an arms race against an attacker who gets to keep trying, and eventually I lose it. Enforcement is a different problem. Finding every hidden instruction in every image forever is not a problem I can solve. Making sure an untrusted image cannot create an admin account, whatever it says, is a rule I can write down and test. Screening still helps, by cutting the volume and flagging what deserves a person's attention, but the plan check is the barrier.

An attack channel not covered

A CISO I have been talking with pointed me at an example of visual prompt injection, in a demonstration the security firm DeepKeep published under the name INKJECT. The technique hides instructions inside an image. White text on a white background, or characters skewed enough that a scanner sees garbage while the model reads them fine. You leave the image somewhere an agent will fetch on its own, a public repository or a shared asset library. Someone asks the agent to deploy the site. The agent takes in the image the way it takes in everything else, follows the buried instruction, and quietly creates an admin account the attacker controls. The site deploys correctly. The text guardrails stay green. A model that refuses a typed instruction can still act on the same instruction embedded in an image, because the image reaches it through a channel the text defenses do not address. A benchmark presented at a major machine learning conference tested this attack against agents that operate a computer or a browser on the user's behalf, and found them following it at high rates on common platforms, with existing defenses barely moving the numbers.

Whenever I am introduced to new research or scenarios I see this as a chance to pressure test my design approaches, in this case there was room for improvement.

The separation of plan from execution covers trying to address the malicious plan, but my data trust system was built for text.

What broke was the entry, the layer that tags and screens inbound content assumed the content was text, so a retrieved image walked in untagged and unscreened. The attack does not touch the text layer. It comes in through the part of the model that reads images, upstream of the text controls I had.

What held was the design of the check. What did not hold was the input it needs.

The rule reads a label and an action. The injected instruction produced a step that creates an admin account, and that is a privileged action, so half of what the rule needs was present. The other half was missing. My trust tagging is built for text, so the image arrived carrying no label, and a rule that keys off a label has nothing to fire on.

Something would have stopped this attack anyway, and it is not the architecture. There is no tool in my registry that creates an admin account. The planner can only propose from a fixed list, and a step naming a tool outside that list gets rejected on the way in. That check is real and it runs today. It is also luck. It caught this one because the attacker happened to ask for something my tool list does not contain, not because anything recognized an attack.

Swap the injected instruction for something inside the list, write a file, or fetch a URL with data sitting in the query string, and the registry check passes cleanly. The trust rule is what should catch it then. The trust rule has no label to read.

So the plan check works the same no matter which channel the content came through, but the tagging that feeds it was built for text alone. Text gets a label and an image does not, which leaves the check I designed waiting on an input it never receives. Building that is work I have not done.

That is the difference between guarding the input and guarding the plan. A boundary on the input has to recognize the attack, which means it has to have seen something like it before. A boundary on the plan does not. It notices that untrusted content is about to drive a privileged action, and it never has to know what the attack was.

What the plan check makes enforceable

Three other defenses depend on it.

Data trust at ingestion. Content gets tagged with where it came from the moment it arrives, and the tag has to cover every channel the model can read from. Mine covers text. An image, a PDF with an image inside it, a repository README, they all reach the model and none of them arrive labeled. That is the entry work INKJECT exposed, and I have not built it.

Egress as its own category. Anything that leaves for the outside world gets its own rules at the executor. EchoLeak is the case that proves it, because it leaked data without calling a single tool, through a rendered image the client fetched on its own. The executor is where that decision has to sit, because the model's own output is one of the ways data gets out.

Then I ran INKJECT against my own tool list. My registry sorts tools by what they do, and fetch_url is filed as a read. Fetching a URL is not a read. Data leaves in the query string. A plan that reads a file and then fetches a URL with the contents attached passes every check I have described, because both tools are registered, both arguments validate, and neither one is classified as sending anything.

The check is only as good as the classification underneath it. The code did its job. The taxonomy was wrong.

Which plans a person sees. A cheap screener can sort the plans that are obviously fine from the ones worth a human's attention, so the confirmation prompt appears when it matters and stays quiet when it does not. Triage is a separate piece of work, and it has something to sort only because the plan is an object in the first place.

I am writing about each of these on its own. Without the plan and the executor, each one is a suggestion the model is free to ignore.

What this does not solve

The separation is necessary and it is not sufficient.

It catches the effect and not the entry. The image still got in, and until the tagging covers every channel the model reads from, it will keep getting in.

The check is strongest when the injected step asks for something the task never needed. It weakens as the injected action moves toward something the task legitimately does. If a job genuinely needs to write files, an injected write to a different path is the same kind of action, and the classification passes it. What catches it then is the trust label, if the content that produced the step was tagged, and the limits on the tool itself, a write confined to the working directory, a fetch confined to an allowed host.

The design also depends on two things staying true. A model that can act without emitting an inspectable plan defeats it. So does an executor that waves steps through, or a person who clicks approve on a confirmation prompt without reading it. The structure creates a place to enforce. It does not enforce anything on its own.

My own build is earlier than this piece might suggest. The planner produces validated, inspectable plans today. There is no executor. The tools are stubs that raise an error if anything calls them, the trust rule and the classification and the human review are all specified and unbuilt, and nothing is enforced end to end because nothing executes. This is a design I am partway into, not a system I am running. I would rather say that than let the piece imply otherwise.

Why an explicit plan is worth the trouble

The mechanism matters less to me than what it made possible when INKJECT showed up.

The attack was not in my design, and I did not redesign anything to answer for it. I walked it through the pieces I already had and got specific answers. The tagging is built for text, so the image entered unlabeled. With no label, the rule had nothing to check. The registry has no admin account tool, which is what killed the step, by luck. And the egress classification is wrong, so a subtler version would have walked straight through.

Each of those answers is a work item. Images get tagged at ingestion. The tool that fetches a URL gets classified as something that sends data, because that is what it does. Neither change is a redesign, and both came out of walking someone else's attack through my own architecture.

That walk is possible because the plan is a real object with a written rule attached to it. An architecture that lives only in intentions has nothing to test an attack against. This one does, which means every new piece of research is a chance to find the next gap before an attacker does.

Put the boundary where it can be inspected and enforced, on the plan, and the model can be as untrustworthy as it is going to be anyway.

If you are building or buying an agent that will hold real credentials, ask one question. When the model proposes an action, is there something outside it that can refuse? Or is the model both the thing that decides and the thing that acts?

By the Numbers

An independent stress test of Claude Code's auto mode permission classifier reported an overall false negative rate of 81% across 128 prompts and 253 adversarial actions, against the vendor's own published figure of 17%. The classifier is the production attempt to move the security decision off the model, and under adversarial workload it still misses most of what it should catch.

Ji et al., 'Measuring the Permission Gate: A Stress-Test Evaluation of Claude Code's Auto Mode,' arXiv:2604.04978, April 2026

Securing AI agents against prompt injection requires information flow control on the data the agent reads, so the framework knows when a proposed action has been influenced by external content. Permission gating on tool calls alone is insufficient without that provenance traveling with the data.

Costa and Köpf, 'Securing AI Agents with Information-Flow Control,' arXiv:2505.23643

A benchmark of 306 visual prompt injection test cases across five web platforms measured how often agents follow instructions embedded in what they see rather than in text. Computer-use agents were deceived at rates up to 51%, and browser-use agents up to 100%, on some platforms. Fine-tuning and proprietary defense layers helped only partially, and system prompt defenses were largely ineffective.

Cao et al., 'VPI-Bench: Visual Prompt Injection Attacks for Computer-Use Agents,' arXiv:2506.02456, ICLR 2026