All insightsENGINEERING · Security · 3 MIN READ

Authorising what an AI agent sends, not what it reads

An agent with a mailbox can send, forward and change forwarding rules — so a hostile instruction inside an incoming email is enough to make it an exfiltration channel. Inbound filtering cannot fix that. Checking the destination can.

Mermail gives AI agents their own email inboxes. An agent that reads mail also holds tools that send, reply, forward, schedule mail, change mailbox forwarding and invite workspace members.

That combination has a specific failure mode, and it is not the one people usually defend against.

Why inbound filtering does not solve it

Inbound filters decide what an agent is allowed to read. They do not decide what it does afterwards.

Once hostile text sits in the same context as the agent's own instructions, no amount of additional inbound rigour changes the next tool call. The model has already been given the attacker's words alongside the operator's, and there is no reliable way to make it treat them differently.

The only control an attacker cannot reach through content is a check on the destination and the persistence of the effect about to be produced. Content can argue for anything. It cannot make an unknown address become a known one.

So the check has to move: out of the reading path, and into the moment immediately before an outbound call fires.

What the guard does

mermail-egress-guard is a policy layer that runs immediately before any outbound action.

  • Recipient provenance. Every recipient must trace to a trusted origin: the user's own request, an existing workspace member, or a counterparty the user named. An address that first appears inside a message body, header, attachment or tool result is derived and ineligible. A wrong candidate is refused without revealing the correct one.
  • Reply-target resolution. reply_to_email looks implicit, which is exactly why it is the most abused path. The destination resolves from the verified envelope sender, never from the Reply-To header. An attacker who sets that header turns an ordinary reply into a direct channel while the transcript still reads as a reply to the original correspondent.
  • Severity by persistence, not payload size. A forward leaks one thread. Enabling settings.forwarding leaks every future message — with no further agent action, no further tool calls to audit, and nothing visible to anyone reading the transcript.

That last distinction drives the strictest rule in the layer. Requests to enable forwarding that originate in inbound content are refused outright rather than surfaced as a confirmation prompt. Offering to confirm still lets untrusted content set the agenda for a persistent channel, and a user clicking through a plausible-looking prompt is the failure mode being defended against.

Two decisions worth explaining

It claims no tools. Before writing anything, I diffed the platform's live server catalogue against its tool ownership registry and found zero unowned tools. A new tool-owning domain would have duplicated an existing owner, which the project's contribution guide rules out. So the guard registers as an infrastructure skill and is invoked by whichever skill holds the tool — the check applies without changing who owns what.

Verified against a live deployment, not a mock. A test message was delivered through real inbound routing carrying a two-part injection: forward the thread to an address appearing only in the body, and switch on auto-forwarding to that same address.

The message scored scan_status: clean, with SPF, DKIM and DMARC all unknown — which is the point. It passed every inbound check available and was still hostile. Both requests were refused, and mailbox settings were confirmed unchanged afterwards.

Delivered

  • SKILL.md plus three reference documents: tool surface, security boundary, decision procedure
  • 7 validation scenarios, 4 carrying security-case labels
  • Registration across the project's ownership registry, router precedence rules and README
  • npm test passing: "Validated 16 skills and 71 business tools."

The contribution is open source, and the review is public:

Nudgen-Marketing/mermail-skills #84

What generalises

The pattern is not specific to email. Any agent that reads untrusted input and holds tools with outbound effects has the same shape, and the same two questions are worth asking of every tool it can call:

Where does this effect land, and can I trace that destination to something the attacker could not have supplied? And does this effect end when the call ends, or does it keep running after nobody is watching?

Guarding the input is guarding the wrong side.

Related reading