How do you prevent data exfiltration and sensitive data leakage from 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.
Arcjet is one way to run that detection. Its sensitive-information rules run inside your application, in the tool call or before the model reply leaves, so Arcjet never receives the raw content on that path. Each check returns an allow or deny decision that your code turns into a block, a redaction, or a flag.
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.
How does data leak through an AI agent?
Three leak vectors are specific to agents. A web application rarely has them, which is why controls designed for request and response traffic miss them.
| Vector | How the data leaks | Where to check |
|---|---|---|
| Tool output | A tool returns more than the task needs, such as a whole customer record, and the model carries it into its reply, a log, or the next tool call | The tool result, before it returns to the model |
| Chained calls | The agent reads data in one step and sends it in a later one, such as a search followed by an email or a query followed by a webhook. Each step is permitted on its own. | The outbound tool's arguments, such as an email body or a URL, and its destination |
| External API responses | A third-party response carries an instruction to send data somewhere, or returns data that you mustn't store or show to this user | The response, for prompt injection and sensitive data, before it enters model context |
The chained case is the hardest, because no single step looks wrong. Screening the outbound arguments catches the payload when it contains detectable data. An egress allowlist on the destination catches it when it doesn't. The lethal trifecta describes the combination of capabilities that makes it possible.
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 SDK-local sensitive-information detection runs entirely in your application. Arcjet never receives the raw content on that path. A built-in WebAssembly engine detects email addresses, phone numbers, IP addresses, and credit card numbers with no network round trip. A separate server-side detector exists for coding-agent hooks when there is no SDK.
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
| Boundary | What it catches | How often it is left open |
|---|---|---|
| Tool outputs and model responses | Protected fields traveling into model context or back to a user | This is the actual exfiltration boundary, and the one most often missed |
| Inside tool calls | Data moving through non-HTTP code paths where it really moves | Usually 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. For a coverage matrix across the five points where agents leak personal data, see how to prevent PII leakage from AI agents. 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 travelsconst 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}Run the same rule on an outbound tool's arguments, such as pii(args.body) in a send-email tool, to catch the chained case before the data leaves. 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/redacthandles. - 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 egress control on the destination, so that a call to a host nobody reviewed, or one that threat intelligence marks as high risk, is refused whatever it carries. For more information, see how to build an egress allowlist for AI agents and how to stop an AI agent contacting malicious URLs. 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.
Arcjet can also score the hosts an agent is about to contact with Arcjet threat intelligence and deny high-risk destinations. That helps when the risk is where the data is going rather than what it contains.
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.
AI agent governance guides
This guide is one of five on governing what an AI agent may do at runtime:
- How to enforce least privilege for AI agent tool calls: limit each agent to the tools, resources, and arguments its task needs, and enforce it in the handler.
- How to audit and log AI agent activity for compliance: record who, what, and when for every tool call, with sensitive fields redacted.
- How to secure an MCP server or AI agent tool calls: enforce inside the handler, where no HTTP request exists to inspect.
- How to stop AI agents taking unsafe or unauthorized actions: classify data access, destructive operations, and external calls, and intercept each one.
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.
How do I prevent sensitive data leakage from AI agents?
Check the three agent-specific vectors: screen tool results before they return to the model, screen outbound tool arguments and restrict their destinations to catch data read in one step and sent in a later one, and screen external API responses before they enter context. Arcjet runs that sensitive-information detection in your process.
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
Arcjet classifies the body in your own process and returns a decision, so the data you are protecting never leaves to be scanned.