# Microsoft Presidio: masking PII before you call an LLM, and why its own documentation won't promise to catch it all

> This open-source library gives you a personal-data filter that sits in front of the model. Out of the box it ships only English models, and it says plainly that it will miss things.

Original: https://fdetimes.net/en/tools/microsoft-presidio-pii-masking-before-llm/

Presidio's documentation contains one sentence every FDE should read before plugging it into a customer's system: there is no guarantee that Presidio will find all sensitive information. A library built to mask personal data admits that it will miss some. Understanding that admission is the first step to using it properly.

When you build an agent or chatbot on top of support tickets, patient records or customer email, the first question from the security team is usually: does personal data leave for the model provider?

Presidio is an open-source tool for answering that question. But if you simply install it and nod that "PII is masked", you are promising something its own authors will not.

## What Presidio does, in two modules

Presidio started as the microsoft/presidio repository and has since moved to data-privacy-stack/presidio, with documentation now at presidio.dataprivacystack.org. The project describes itself as modules for identifying and anonymising private entities in text and images, released under the MIT licence.

The first module is the Analyzer. It runs a set of recognizers, each detecting one or more PII types with its own mechanism: an NER model, regex, or other logic. It ships with global entities such as credit card numbers, email addresses, IP addresses, URLs, PERSON, LOCATION and PHONE_NUMBER, plus some country-specific types for places such as the US, the UK, Singapore and Thailand.

The second module is the Anonymizer, which decides what to do with what was found. Its operators are replace, redact, mask, hash, encrypt and custom. Encrypt alone is reversible, using the deanonymizer's decrypt operator with the same key, so you can mask data before sending it to the model and then restore the original values for the user.

## What happens when a ticket goes through Presidio?

Picture a bank customer submitting a ticket written in Vietnamese: full name, email address, card number and an internal customer ID in the form "KH-482913". The email and card number follow fixed patterns, so Presidio's regex will most likely catch them. The name is another matter.

The default NER model is spaCy's en_core_web_lg, an English model. The documentation states that by default only English recognizers and models are provided; supporting another language means extending both the NLP engine and the recognizers, and each language can use only one NER model. A Vietnamese name in the middle of a Vietnamese sentence can easily slip past an English model.

The ID "KH-482913" will certainly get through, because no built-in recognizer knows it. The default entity list also lacks the national documents of many countries, such as Vietnam's citizen ID card or tax code. The fix is to write a PatternRecognizer: a regex for the ID format, plus context words such as "customer ID" and validation logic if needed.

A detail that is easy to forget: context words depend on language. English context words applied to Vietnamese text are close to useless. And regex catches only what has a pattern: if a support agent types the ID in the wrong format, say without the hyphen as "KH482913", a regex written for "KH-482913" will not recognise it.

## The return path is where teams forget

A common deployment puts Presidio at the gateway layer, masking PII before a request reaches the model provider; the official samples page includes an example of doing exactly this with an AI gateway. LiteLLM also has a guardrail that uses Presidio, but you must deploy both the Analyzer and Anonymizer containers yourself.

The trap lies in LiteLLM's output_parse_pii flag. The documentation is clear that it only swaps masked tokens back to their original values after the model call; it does not run PII detection on the response. To scan the response as well, you must set presidio_filter_scope to output or both.

One more thing the customer's security team will ask about: Presidio's API endpoints have no built-in authentication, by design. You have to put them behind an authentication layer in your infrastructure; otherwise the PII-masking service becomes an open door to the very PII it is meant to protect.

## Knowing the limits is what lets you sell it

Presidio's FAQ says plainly that all detection logic makes errors, and that reducing false positives comes at the cost of more misses.

It also acknowledges that SaaS PII services often cover more entities or are more accurate, and that Presidio is not an official product of any company, with no warranty and no SLA.

The documentation therefore recommends adding other layers of protection.

When presenting to a customer, put Presidio in its proper place: one layer among several, backed by measured numbers.

Before the demo, hand-label a sample of the customer's real text, run it through the pipeline, and report how many entities slipped through, by type.

When customers see that you found the gaps yourself first, they trust you more than they would a promise that "everything is masked".

**Key point:** A PII-masking layer is only trustworthy once you have measured what it misses.

A sensible learning order: get to grips with the Analyzer and Anonymizer on English text, then write a PatternRecognizer for a customer-specific identifier, then try configuring the NLP engine for another language, and finally deploy behind an authenticated gateway that scans both directions.

On a CV, a line such as "built a PII-masking layer in front of an LLM, measured the miss rate on a labelled data sample, wrote recognizers for internal identifiers" shows employers that you understand deployment with real data, not just calling an API.

Customers will not ask whether you use Presidio. They will ask what still leaks out, and you should be the one with an answer in numbers.

**Try this week:**

- Take 50 passages of a customer's real text (with permission to use them), mark the PII by hand, run default Presidio and count how many entities slip through.
- Write a PatternRecognizer for one of the customer's internal identifiers, with context words in the language the customer actually uses.
- If you use LiteLLM, check presidio_filter_scope: unless it is set to output or both, the model's responses are not being scanned.

## Sources

- [Home - Presidio](https://presidio.dataprivacystack.org/)

- [Presidio - Data Protection and De-identification SDK (GitHub)](https://github.com/microsoft/presidio)

- [Frequently Asked Questions (FAQ) - Presidio](https://presidio.dataprivacystack.org/faq/)

- [Presidio Analyzer - Presidio](https://presidio.dataprivacystack.org/analyzer/)

- [Customizing the NLP model - Presidio](https://presidio.dataprivacystack.org/analyzer/customizing_nlp_models/)

- [Multi-language support - Presidio](https://presidio.dataprivacystack.org/analyzer/languages/)

- [PII entities supported by Presidio - Presidio](https://presidio.dataprivacystack.org/supported_entities/)

- [Presidio Anonymizer - Presidio](https://presidio.dataprivacystack.org/anonymizer/)

- [PII, PHI Masking - Presidio | liteLLM](https://docs.litellm.ai/docs/proxy/guardrails/pii_masking_v2)

- [Samples - Presidio](https://presidio.dataprivacystack.org/samples/)
