Your AI Agent Knows Too Much A developer built a tokenization guardrail for AI agents that prevents sensitive data from reaching large language models. The system replaces real customer data with opaque tokens, swaps them back only during tool execution, and rejects any non-token arguments. The approach, implemented as Microsoft Agent Framework middleware in about 150 lines, addresses data leakage risks from model traces, logs, and hallucinated tool calls. Most AI agent examples make the same mistake. They show a nice prompt, a clean tool call, and then quietly pass raw real data straight through the model. That works for a demo, but it is a very bad idea in production. A prompt is not just text anymore. It is part of the execution path. If you put real customer data into it emails, user addresses, their real names , that data can leak through traces, tool calls, or the final answer. TL;DR The model gets an opaque token, never the real value. A guardrail swaps the token back for the real value just before the tool runs, then scrubs it out of the result. The model only ever holds tokens, and anything that is not a live token is rejected. The whole thing is Microsoft Agent Framework middleware, around 150 lines. Demo repo: github.com/bgener/demo-maf-tokenization https://github.com/bgener/demo-maf-tokenization A bare integer or a GUID is mostly harmless. Real data is not, and I do not just mean passwords. Think phone numbers, home addresses, someone's location. Two things go wrong the moment the model holds it. It can leak: repeated in a reply, written to a log, or shown to the wrong user. And models make things up. A confused agent will invent arguments and call your tools with nonsense. If your tools trust whatever the model sends, that nonsense reaches your real systems. Maybe you use Anthropic directly. Maybe Azure AI Foundry or Amazon Bedrock with good privacy terms. That helps, but it does not remove the problem. Because "Not used for training" is not the same as "never exposed anywhere". The data can still move through provider infrastructure, safety systems, logs, traces, tool calls, prompt history, evaluation runs, or the final answer. With tokenization, the model never sees the real value. You hand it an opaque token instead, something like tkn loc ab12... . When the model calls a tool, it passes that token back, and you swap it for the real value just before the tool runs. So when the agent invents a token, or fires ten calls with junk arguments, none of it lands. A made-up token matches nothing in the registry, and the call is rejected. The layer that enforces it around a tool call is a guardrail, and the step that keeps the real value out of the model's reply is output redaction. Put it together and you get a tokenization guardrail with output redaction. We need somewhere to keep the map between real values and tokens. The TokenRegistry holds it in memory. It maps each token to its real value, and each real value back to its token, so the same value never mints two tokens. public sealed class TokenRegistry : ITokenRegistry { readonly ConcurrentDictionary