Skip to content
cd ..

Defense in Depth: Client Side and Server Side Outbound Scanning

// · 5 min read

When an AI agent sends email, there’s a real risk it leaks something it shouldn’t. API keys, credentials, personal data, internal system details. The agent might not even realize it’s doing it. A prompt injection hidden in an incoming email could trick the agent into forwarding sensitive context. A poorly written agent could dump its entire working memory into a reply.

AgenticMail addresses this with two independent scanning layers: one in the MCP client, one in the API server. Neither layer trusts the other. Both enforce their own rules. This is defense in depth applied to outbound email.

Layer 1: MCP client side scanning

The MCP server includes a set of 35 regex patterns called MCP_OB_RULES. These patterns run against every outbound email before it leaves the MCP process. The scanning happens before the HTTP request to the API server is even constructed.

The 35 patterns cover common sensitive data formats:

Credential patterns catch API keys, bearer tokens, AWS access keys, private keys in PEM format, and connection strings with embedded passwords. These are the most dangerous leaks because a single exposed credential can compromise an entire system.

Personal data patterns detect Social Security number formats, credit card numbers (with Luhn validation on the regex match), phone numbers in various formats, and email address clusters that suggest a contact list dump.

Internal system patterns flag things like internal IP addresses, localhost URLs with port numbers, file system paths, stack traces, and environment variable dumps. These reveal infrastructure details that should never appear in outbound email.

AgenticMail specific patterns catch agent configuration blocks, database connection strings, and vault access tokens. If an agent somehow includes its own credentials in an email body, this layer catches it.

When a pattern matches, the MCP server returns an immediate error to the model. The email never reaches the API. The error message tells the model which rule triggered and which part of the content matched, so the model can revise the email and try again.

This client side scanning exists for speed and developer experience. The model gets instant feedback without a network round trip. It can iteratively fix the email content in conversation with the user.

Layer 2: API server side guard

The API server has its own outbound guard that runs independently. Every email that hits the send endpoint passes through this guard before reaching the SMTP relay.

The server side guard is more sophisticated than the MCP patterns. It has two modes:

Blocking mode rejects the email outright and returns a 422 response with details about what triggered the block. This is the default for high confidence detections like PEM private keys or AWS secret keys.

Pending mode accepts the email but holds it in a pending queue instead of sending it. The email sits in quarantine until a human operator reviews and approves it. This is for lower confidence detections where the content might be legitimate (a support email that happens to contain a stack trace, for example).

The server side guard also has access to context the MCP layer doesn’t. It can check the recipient against known external domains, cross reference the content against the agent’s configured allowed data categories, and apply per account custom rules.

Why two layers matter

You might wonder why both layers are necessary. If the API server catches everything, why bother scanning in the MCP client?

Three reasons.

First, not every client goes through MCP. The API is a REST server. Any HTTP client can call it. A custom integration that skips the MCP layer entirely still gets protected by the server side guard. The server side guard is the authoritative enforcement point.

Second, the MCP layer provides better UX. When a model is composing an email in conversation with a user, instant feedback from the MCP layer lets the model fix the issue in the same turn. A round trip to the API server and back adds latency and breaks the conversational flow. The MCP patterns are optimized for fast, inline correction.

Third, defense in depth means no single point of failure. If a bug in the MCP scanning logic lets something through, the server side guard is still there. If the server side guard has a gap, the MCP layer might have caught it already. The two layers use different implementations, different pattern sets (with significant overlap), and different matching strategies. A bypass that works against one is unlikely to work against both.

The tradeoff

Running 35 regex patterns against every outbound email adds latency. In the MCP layer, it’s a few milliseconds since the patterns run in memory against a string. In the API layer, it’s slightly more because the guard also does database lookups for custom rules and recipient checks.

For email, this latency is invisible. Nobody notices an extra 10 milliseconds on an operation that involves SMTP delivery. And the alternative, an agent accidentally emailing a private key to an external recipient, is catastrophic enough that the scanning cost is trivially justified.

Two layers, independent implementations, overlapping coverage. It’s more work to maintain than a single scanner, but when you’re giving AI agents the ability to send email to the outside world, you want every safety net you can get.

Source Code

Both scanning layers are available in the repository:

View the client side scanner on GitHub

View the server side guard on GitHub

// share

// subscribe

New posts and updates straight to your inbox. No noise.

cd ..