AI agent security

How to Prevent Data Exfiltration Through AI Agents

Detect protected data at the boundaries where it moves, and run that detection in your own process so the inspection does not become a second export path. Tool outputs, logs, and embeddings are the boundaries most often left open.

7 min read
In short: Detect protected data at the boundaries where it moves, and run that detection in your own process so the inspection does not become a second export path. Tool outputs, logs, and embeddings are the boundaries most often left open.

How do you prevent data exfiltration through AI agents?

You detect protected data at the boundaries where it moves. Do that detection in your own process, so that the inspection itself does not become a second export path. The boundaries that matter are tool outputs, model responses, logs, traces, and embeddings, in roughly that order of how often they are left open.

An agent is an efficient data mover. It reads from your systems, summarizes, and passes results onward. Point that capability the wrong way, through an injection or a design mistake, and it is an exfiltration path with valid credentials.

The scanner problem

So you add data-loss prevention (DLP). This is where most AI DLP projects stall.

To inspect the data, the tool has to receive the data. A cloud scanner reading your request bodies means protected content leaves your environment to be checked. You have built a second export path to prevent the first, and privacy review says so.

The objection is not pedantic. Every vendor that receives request bodies becomes an in-scope processor, with an agreement, a sub-processor disclosure, and a transfer question attached. A control that adds a recipient of personal data to detect personal data is difficult to defend as minimal.

Inspect without moving anything

Arcjet's sensitive-information detection runs entirely locally, in your application. Arcjet never receives the raw content. A built-in WebAssembly engine detects email addresses, phone numbers, IP addresses, and credit card numbers with no network round trip.

For broader coverage, an optional on-device machine learning model covers names, physical addresses, national identifiers, bank account and routing numbers, and passport and driver's license numbers. The published model card lists it at around 14.7 MB when 4-bit quantized, with roughly 6.6 ms median inference on Node.js.

Rate limiting and prompt-injection detection call Arcjet's cloud, because one needs shared counters and the other needs a specialist model. For more information about the architecture argument for keeping content inspection local, see keeping security inspection local.

Where to put the check

BoundaryWhat it catchesHow often it is left open
Tool outputs and model responsesProtected fields traveling into model context or back to a user

This is the actual exfiltration boundary, and the one most often missed

Inside tool callsData moving through non-HTTP code paths where it really movesUsually uncovered entirely, because no request exists to inspect
Inputs

Protected data being logged, embedded, or written to a vector store it should not reach

Often covered for the user-facing path and missed for the storage path

Checking only the user-facing response is the common shape, and it leaves the durable copies unprotected. Logs and embeddings are where regulated data quietly accumulates, and they are typically retained far longer than the request that produced them.

Detect inside a tool call

import { launchArcjet, localDetectSensitiveInfo } from "@arcjet/guard";
const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });
const pii = localDetectSensitiveInfo({
deny: ["EMAIL", "PHONE_NUMBER", "CREDIT_CARD_NUMBER"],
});
// Run the check on what the tool is about to return, before it travels
const result = await queryCustomerData(args);
const decision = await arcjet.guard({
label: "tools.query-customer-data",
actor: session.userId,
correlationId: workflowRunId,
rules: [pii(JSON.stringify(result))],
});
if (decision.conclusion === "DENY" || decision.hasFailedOpen()) {
// Block, redact, or flag, depending on the code path
}

The rule name says where it runs: localDetectSensitiveInfo evaluates in your application, not in Arcjet's cloud. A direct Guard call fails open (allow with error codes). The sample stops the tool when hasFailedOpen() is true. Vercel AI SDK and LangChain wrappers fail closed unless you opt into continuing on error.

Then decide what to do

Detection gives you a decision to act on, and the right response differs by code path.

  • Block where the data should never have been there, and where failing the operation is safe.
  • Redact where the operation must still complete without the protected span, which @arcjet/redact handles.
  • Flag where you are still measuring and do not yet trust the detection enough to act on it.

Because it is a rule in your code, you choose for each code path with full context, and Arcjet records each decision with its label and metadata for later inspection.

One layer of several

Local DLP does not stand alone.

Pair it with least-privilege tool design, so an agent cannot reach data that it never needed. Pair it with injection detection, so the agent is harder to misdirect in the first place. Pair it with budgets, so a hijacked agent cannot loop. Detection has real false-negative rates and those rates move as data shapes change, so it belongs alongside controls that do not depend on recognizing content.

The point is to make trust boundaries visible in code, and to keep the data inside your infrastructure while you do it.

The version this does not solve

The hardest exfiltration case has no detectable payload at any single boundary. An agent reads a customer list in one step and calls an export tool two steps later. Both actions are permitted. Neither output, inspected alone, looks like exfiltration, because each one is a legitimate result the agent was allowed to produce.

Catching that requires policy that carries earlier steps into the current decision. It is a frontier problem in this field rather than a solved one, and per-boundary detection does not address it. You can tag every decision with the workflow run, so that the sequence is reconstructable. That identifier does not change an allow or deny.

Where Arcjet fits

Most AI data-loss prevention products are cloud scanners: you send them the content, they classify it, you act on the verdict. That model works, and it puts a new processor in the path of your protected data.

Arcjet is the in-code enforcement layer, and its sensitive-information detection runs in your application. Arcjet never receives the raw body, so the inspection does not add a recipient of the data it is inspecting. The decision returns to your code, which chooses for each code path whether to block, redact, or flag.

It is one layer of several. It does not replace least-privilege tool design, and it is not a discovery tool that tells you where regulated data lives. For more information about how the layers divide, see the category map.

Learn more: AI data loss prevention · Running PII detection locally with an on-device ML model

Frequently asked questions

How do I prevent data exfiltration through AI agents?

Run sensitive-information detection at the boundaries where data moves, which are tool outputs, model responses, logs, traces, and embeddings. Do the detection in your own process so the inspection itself does not add a third party that receives the protected content.

Why do cloud DLP scanners stall in privacy review?

To inspect the data they have to receive the data, which makes the vendor an in-scope processor and creates a transfer question. A control that adds a recipient of personal data in order to detect personal data is hard to defend as minimal.

Which boundary is most often left unprotected?

Tool outputs and the durable copies. Teams usually check the user-facing response and miss logs, traces, and embeddings, which is where regulated data quietly accumulates and is typically retained far longer than the request that produced it.

Should I block, redact, or flag when PII is detected?

Block where the data should never have been there and failing the operation is safe, redact where the operation should still complete without the protected span, and flag where you are still measuring and do not yet trust the detection enough to act on it.

AI runtime security in your code

Protect your AI agent workflows with Arcjet

Get allow, deny, and redact on agent actions before the side effect.