Ask a vendor how their email agent is wired and you'll often get a diagram with one box in the middle. Inbox goes in, model sits in the box, actions come out. Everything the agent can do, it can do from that one box.
Now ask what happens when a single malicious email reaches the box.
The honest answer, for most deployments, is that the email reaches everything the agent can reach. Refunds. Address changes. CRM records. Whatever the integration credentials permit. There's no boundary between the part of the system that reads untrusted text and the part that changes the world, because nobody drew one.
Filters are a layer, not a plan
The standard response to this risk is detection. Scan the inbound message, score it, block what looks like an attack. That's worth doing, and it's the weakest thing you'll build.
The reason is asymmetry. A detector is a probabilistic classifier facing an attacker with unlimited attempts and immediate feedback about whether an attempt worked. Given enough tries, something gets through. This is the same reason spam filtering never finished, except spam filtering fails safe and an agent with write access fails expensively.
So the question worth designing around isn't how to stop every bad instruction. It's this: when one gets through, how much can it actually do?
That number is your blast radius, and unlike detection accuracy, it's something you control precisely.
Splitting the box in two
The architectural move is straightforward to describe and takes real discipline to hold: separate the component that reads untrusted content from the component that can take action.
The reader ingests the email, the thread history, and any attachments. It has no write tools. None. Its entire output is a structured proposal — an intent classification, a set of extracted fields, a confidence score, and a suggested action drawn from a fixed enumeration.
The doer takes that structured object and executes. It has the write credentials. It never sees the raw email.
That last sentence is the whole design. If the executing component never processes attacker-controlled prose, prose can't instruct it. An injected instruction sitting in the email body has to survive translation into a rigid schema to have any effect, and a demand to ignore the rules and refund an order at full value doesn't translate into a refund call with a validated order ID and an amount inside policy limits. It gets dropped on the floor at the boundary.
This is a specific and stricter version of the pattern described in most multi-agent email workflows. Splitting an agent into a triage step and a resolution step is common. Splitting it so that the resolution step is structurally incapable of receiving free text from the customer is not, and it's the part that carries the security benefit.
What it looks like on a real ticket
Take a refund request. The reader gets the message, the thread, and a photo of a damaged item. It resolves the customer against the account, classifies the intent as a damage refund, pulls the order reference from the thread, and emits something like: intent is refund, order is 4471-2290, reason code is damaged-on-arrival, amount is 84.00, evidence attached, confidence 0.91.
Six fields and an enum. That's everything crossing the boundary.
The doer then re-checks the order against the customer's account, confirms it's inside the return window, confirms 84.00 matches the line total, confirms the amount sits under the workflow's ceiling, and executes. If an attacker had buried instructions in the image or the email body, they had exactly one channel to influence any of this: the six values above, every one of which gets validated against a system of record the attacker doesn't control.
What the boundary has to enforce
A schema alone doesn't help if the schema has a free-text field that gets passed through. Some rules that make the split real:
- Enumerated actions only. The doer accepts a closed set of operations. There's no generic call-any-API tool, because that tool is a shell for whatever the reader was talked into.
- Validated parameters. Order IDs must exist and belong to the authenticated customer. Amounts must fall within configured limits. Dates must be plausible. Validation runs in the doer, not in the model.
- No pass-through prose. If customer-supplied text has to reach a downstream system, it goes in a field that system treats as display data, never as instruction.
- Separate credentials. The reader's environment holds no write tokens at all. Not scoped-down tokens. None.
The reply the customer receives is generated by the reader and can be as fluent as you like, because generating text is a read-side activity. The value here comes from the split, not from making the agent terse.
Least privilege, in the boring practical sense
Even with the reader and doer separated, the doer's permissions decide what a compromised proposal can accomplish. Most teams get this wrong in the same way: one integration user, one API token, every scope the platform offers, provisioned once during onboarding and never revisited.
It's understandable. Scoping credentials per workflow is fiddly, and nobody wants a deployment blocked because a token is missing a permission. The cost shows up later.
A better default is one credential per workflow, each carrying the narrowest scope that workflow needs. The refund workflow gets refund permissions on orders and nothing else. The address-change workflow can write to shipping fields and can't touch payment methods. The status-lookup workflow is read-only, which covers a large share of your volume and should account for almost none of your risk.
Add ceilings on top of scopes:
- A maximum value per action and a rolling total per hour.
- Destination allowlists for anything that sends data outward.
- Per-workflow rate limits that trip an alert rather than silently queuing.
Ceilings are what turn a bad day into a small bad day. An attacker who defeats every other control and gets a refund issued has gotten one refund, capped, logged, and rate-limited, instead of a script running against your payment provider for six hours before anyone notices.
Gate on reversibility, not on confidence
Most products gate actions on a model confidence score. High confidence, act. Low confidence, escalate.
That's the wrong axis. Confidence measures how sure the model is, and a successful injection produces a confident model. What you want to gate on is what happens if this action turns out to be wrong.
Sort actions by reversibility instead. Sending an informational reply is trivially reversible. Issuing a store credit is reversible with effort. Changing the email address on an account or disabling a security factor is effectively irreversible, because by the time you find out, the attacker has used the window. Irreversible actions get human approval regardless of how confident anything is, and that rule holds even when it costs you resolution rate. If you're weighing where those lines sit, our guidance on resolving versus routing to a human works through the tradeoff in more detail.
Doing the arithmetic
Blast radius is worth calculating rather than asserting. Take a mid-size e-commerce operation running an email agent across refunds, order changes, and status lookups, and assume total compromise of the reader. What's reachable in the first sixty seconds?
With one credential and no ceilings: every order in the store, unbounded refund value, and any field the API exposes. Realistically that's a five-figure loss before an alert fires, plus a data exposure problem you'll be explaining for months.
With per-workflow credentials, a $200 per-refund cap, a $2,000 hourly ceiling, and irreversible actions gated: one refund, capped at $200, on an order that had to already exist and belong to a verified customer. The hourly ceiling trips within a few attempts and pages someone.
Same attack. Same detection failure. Two very different Mondays.
Run this exercise against your own stack and write the number down. It's the most useful security artifact most support teams don't have, and it's also the honest answer to give a security reviewer who asks what happens when the model gets fooled. The read side of the same question, meaning what data an attacker could pull rather than what they could change, is covered in our piece on data exfiltration through support email.
What the split doesn't fix
Two gaps worth being explicit about, because architecture articles have a habit of implying the problem is solved.
The reader still holds data. It has to, since you can't answer a question about an order without reading the order. So an attacker who compromises the reader can't change anything, but they may be able to see things, and the reply the agent sends is a channel out. Least privilege on the write side does nothing about that, and the controls for it are different: redact what the reader retrieves, scope retrieval to the authenticated customer, and constrain what a reply can contain.
The second gap is subtler. A structured proposal is only as trustworthy as the classification that produced it. If an attacker convinces the reader that a legitimate-looking refund is warranted, with no injection involved, just a good story and a real order, the proposal will be well-formed and the doer will execute it. That's not an architecture failure. It's a verification and policy failure wearing an architecture costume, and it's why ceilings matter as much as boundaries.
What this costs
Every article on this topic ends by implying the architecture is free. It isn't.
You pay in latency, because a second component and a validation pass add round trips. You pay in engineering time, because per-workflow credentials mean per-workflow provisioning and a rotation process somebody has to own. You pay in coverage, because a closed enumeration of actions means genuinely novel requests fall outside it and escalate, and some of those escalations will be things the agent could have handled.
The pressure this creates is real and worth naming. Six weeks in, resolution rate plateaus below target, and the fastest fix on the table is widening scopes or adding a general-purpose tool. That decision gets made in a sprint planning meeting rather than a security review, and it quietly undoes the whole design.
The way through is to treat scope changes as a reviewed decision with a recorded rationale, the same as any other production change. Not a ticket someone closes on a Friday.
How Robylon is built
Robylon separates email comprehension from execution as a structural property rather than a configuration option. The component that reads inbound messages and attachments produces a validated action proposal and holds no write credentials. Execution runs through the write-access integrations layer against an enumerated action set, with parameter validation, per-workflow scoping, and value and rate ceilings you set during deployment.
Irreversible actions carry approval requirements independent of model confidence, and every executed action is logged with the proposal that produced it, so a review can trace an outcome back to the message that triggered it. The related risk of an attacker talking the reader into a legitimate-looking proposal in the first place is covered in our article on account takeover attempts via support email.
One question worth asking any vendor in a demo: does the component holding your API credentials ever receive raw customer text? If the answer is yes, or if it takes them a while to work out what the answer is, you've learned something useful.
Ready to deploy an email agent that can act without handing an attacker the keys? Robylon AI resolves 60-80% of customer emails autonomously, executing across Zendesk, Shopify, Stripe, Salesforce, and 60+ other integrations through scoped, validated, rate-limited actions. Start free at robylon.ai
FAQs
What does least privilege mean for an AI agent?
It means each workflow runs with the narrowest permissions it needs, rather than one integration token carrying every scope the platform offers. A status-lookup workflow stays read-only. A refund workflow can issue refunds and can't touch payment methods. Layer value ceilings and rate limits on top of the scopes, so even a fully successful attack produces one capped, logged action instead of an unbounded run.
What is blast radius in AI agent security?
Blast radius is the maximum damage a single successful attack can cause before anything stops it. It's the more useful thing to design around than detection accuracy, because detection is probabilistic and an attacker gets unlimited attempts. Work out what a fully compromised agent could do in sixty seconds, write the number down, and treat it as a configuration you control rather than a risk you estimate.
Should an AI agent use one API key or several?
Several. A single integration user with all scopes is convenient during onboarding and becomes the thing that decides how bad your worst day is. Provision one credential per workflow, each scoped to exactly what that workflow does, and give the component that reads untrusted email no write credentials at all. The overhead is real: per-workflow provisioning and a rotation process someone has to own.
How do you separate reading from acting in an AI agent?
The reader ingests the email, thread, and attachments, and its only output is a structured proposal, meaning an intent from a fixed enumeration plus validated fields. The doer holds the write credentials, accepts only that schema, and never processes raw customer text. Injected instructions have to survive translation into six or so validated values to have any effect, and free-form prose doesn't make that trip.
Does restricting agent permissions hurt resolution rate?
Somewhat, and it's worth being honest about it. A closed action set means genuinely novel requests fall outside it and escalate, including some the agent could have handled. The failure pattern shows up around week six, when resolution rate plateaus and widening scopes looks like the quick fix. Treat scope changes as reviewed decisions with a recorded rationale, not sprint tickets closed on a Friday.

.png)

.png)
