hiddentokens

Hidden Tokens

Hidden Tokens benchmark: detection per industry pack, and leak test

We don't ask you to trust a percentage. Here is what Hidden Tokens detects in each industry, measured on documents it was never tuned on, how it compares with Presidio, what changed in the latest version, what it still misses, and how to check every number yourself.

Updated · HT-Bench 0.2.0, test split · connector 2.28.0

Short answer
  • Direct identifiers: ≥ 99% in every industry pack on HT-Bench (100.0% on the 2.28.0 test split, 2,523/2,523). The test split is 366 synthetic documents that no engine rule was tuned on. Presidio 2.2.358 with its default recognisers detected 77.5% (1,956/2,523) of the same values, scored the same way.
  • From 2.27.0 to 2.28.0: direct identifiers 98.2% → 100.0%; packs below the 99% target 3 → 0; documents whose coded text did not decode back exactly 9 → 0; decoys coded 6.0% → 5.8%.
  • Hidden Tokens also codes fewer things it should not: 5.8% of decoys (amounts, dates, law articles, common words) against 37.6% for Presidio; precision 87.4% against 54.7%.
  • This is a synthetic benchmark. A perfect score here does not mean Hidden Tokens catches everything in real files; addresses, dates of birth and cheque numbers are still missed at times, and the notary pack is not measured yet.
  • These scores, with the French bar's audit of legal AI tools and a market map, are discussed in our annual report, State of AI confidentiality 2026.
  • Separately, the leak test (connector 2.22.0) found nothing identifying readable by the AI in 15 fictional client files: 201/201 sensitive values coded with amounts set to "protect".

HT-Bench: what is detected, pack by pack

HT-Bench is our detection benchmark. It feeds synthetic documents of each industry (call-centre transcripts, court submissions, payslips, medical reports, bank statements, invoices, KYC files) through the Hidden Tokens engine with that industry's pack switched on, and checks every labelled value: coded, partly coded, or left readable. The numbers below come from one run on 25 October 2026, connector 2.28.0, on the test split: documents generated with their own seed, which no engine rule has been tuned on.

PackDocsDirect identifiers detected99% targetRecall, all typesPrecisionF1Decoys codedPresidio, direct identifiers
Telecom (Morocco)
telecom-ma
36100.0% (242/242)met100.0%82.7%90.5%10.8% (17/158)81.8% (198/242)
Legal (France)
juridique-fr
36100.0% (276/276)met97.6%87.2%92.1%9.7% (29/300)82.2% (227/276)
Banking and insurance
banque-assurance
96100.0% (652/652)met100.0%81.7%89.9%3.7% (25/676)64.4% (420/652)
Healthcare
sante
36100.0% (204/204)met95.4%82.7%88.6%11.3% (27/240)86.3% (176/204)
Accounting
expertise-comptable
84100.0% (599/599)met98.5%95.5%96.9%0.1% (1/1,142)81.8% (490/599)
HR and payroll
rh-paie
36100.0% (228/228)met100.0%89.3%94.3%19.9% (74/372)72.4% (165/228)
No pack (general documents)
core
42100.0% (322/322)met98.4%93.5%95.9%2.1% (3/141)87.0% (280/322)
All documents366100.0% (2,523/2,523)all met98.7%87.4%—5.8% (176/3,029)77.5% (1,956/2,523)
Notary (Morocco)
notariat-ma
0not measured: HT-Bench 0.2.0 has no notary documents yet

Direct identifiers are names, ID card, passport and residence-permit numbers, NIR, CNSS, ICE, IF, RC, SIREN and SIRET, phone numbers, emails, IBAN and RIB, IMEI and IMSI, card numbers and security codes. "Recall, all types" adds the other labelled values (addresses, company names, dates of birth, BIC, case, invoice, cheque, policy and claim numbers…). Precision is the share of coded passages that cover a labelled value; it drops when the engine codes ordinary words. The "no pack" row is general documents processed without an industry pack.

What changed from 2.27.0 to 2.28.0

PackDirect identifiers, 2.27.02.28.0Precision, 2.27.02.28.0Decoys coded, 2.27.02.28.0
Telecom (Morocco)
telecom-ma
100.0%100.0%82.7%82.7%10.8%10.8%
Legal (France)
juridique-fr
96.0%100.0%87.1%87.2%9.7%9.7%
Banking and insurance
banque-assurance
99.5%100.0%81.7%81.7%3.7%3.7%
Healthcare
sante
96.1%100.0%81.3%82.7%14.2%11.3%
Accounting
expertise-comptable
99.3%100.0%95.5%95.5%0.1%0.1%
HR and payroll
rh-paie
92.1%100.0%89.2%89.3%19.9%19.9%
No pack (general documents)
core
99.7%100.0%93.5%93.5%2.1%2.1%
All documents98.2%100.0%87.2%87.4%6.0%5.8%

In 2.27.0, 3 packs were below 99% because of a handful of formats. Connector 2.28.0 fixes each of them:

These failures were read and fixed on the development split. Nothing was tuned on the test split, but you should know two things: its 2.27.0 gaps were published on this page before the fix, and they were the same formats, because both splits are built from the same document templates. So the test split shows that the fixes hold on values and phrasings the engine was not tuned on; it does not show how Hidden Tokens handles formats nobody has written a template for yet.

What is still missed

All labelled values together: 98.7% detected, 44 values left readable, all of them outside the direct-identifier target: cheque or bill (LCN) number 75.0% (12 of 48 missed), date of birth 79.1% (18 of 86 missed), postal address 92.4% (14 of 184 missed). The output lock, which re-checks what the AI receives through coder_texte, still masks some codes already placed by a pack (24 in HR and payroll), shown as "•••": the value is protected, but the AI cannot quote the code.

Per entity type: direct identifiers

TypeValuesRecallOf which partialPrecisionF1Presidio, recall
Person names965100.0%080.1% (1,874/2,340)88.9%82.2%
Moroccan ID card (CIN)192100.0%0shared prefix*—69.8%
French social security number (NIR)40100.0%0shared prefix*—32.5%
CNSS number (Morocco)72100.0%0100.0% (72/72)100.0%100.0%
ICE (Moroccan company ID)159100.0%0100.0% (159/159)100.0%66.0%
Tax ID (IF, Morocco)58100.0%0100.0% (31/31)100.0%100.0%
Trade register (RC, Morocco)53100.0%0100.0% (53/53)100.0%88.7%
SIREN24100.0%0shared prefix*—70.8%
SIRET31100.0%0shared prefix*—58.1%
Phone numbers462100.0%0100.0% (430/430)100.0%87.9%
Email addresses200100.0%0100.0% (200/200)100.0%100.0%
IBAN55100.0%0shared prefix*—56.4%
RIB (bank account)109100.0%0shared prefix*—5.5%
IMEI24100.0%0100.0% (24/24)100.0%58.3%
IMSI19100.0%0100.0% (19/19)100.0%100.0%
Payment card number24100.0%055.8% (24/43)71.6%62.5%
Card security code (CVV)12100.0%0100.0% (12/12)100.0%0.0%
Passport, residence permit, driving licence24100.0%0100.0% (12/12)100.0%33.3%

* Precision per type is counted by code prefix, and some types share one: the CIN prefix is also used for NIR and passports, the RIB prefix for IBAN and RIB, the SIREN prefix for SIRET and generic references. For those types a per-type precision would be meaningless, so it is not shown (it is in the raw JSON); the pack precision above is the measure of over-coding. For names, the 80.1% precision reflects the engine coding unknown capitalised words as names: protective, but it gives the AI less to read.

Other labelled types (measured, not part of the 99% target)
TypeValuesRecallOf which partialPrecisionF1Presidio, recall
BIC / SWIFT24100.0%0——8.3%
ICCID (SIM card)12100.0%0100.0% (12/12)100.0%16.7%
Postal address18492.4%0100.0% (173/173)96.0%85.3%
Company name279100.0%064.9% (279/430)78.7%1.8%
Date of birth8679.1%0100.0% (68/68)88.3%66.3%
Patente number (Morocco)5100.0%0100.0% (5/5)100.0%100.0%
EU VAT number7100.0%0100.0% (7/7)100.0%28.6%
Employee ID24100.0%0100.0% (24/24)100.0%33.3%
Patient record number24100.0%0100.0% (24/24)100.0%100.0%
Practitioner ID (INPE, RPPS)36100.0%0100.0% (36/36)100.0%100.0%
Insurance policy number12100.0%0100.0% (12/12)100.0%0.0%
Claim number12100.0%0100.0% (12/12)100.0%16.7%
Invoice number48100.0%0100.0% (24/24)100.0%25.0%
Docket number (RG, parquet)48100.0%0100.0% (36/36)100.0%8.3%
Number plate24100.0%0100.0% (24/24)100.0%37.5%
Cheque or bill (LCN) number4875.0%0100.0% (36/36)85.7%100.0%
Contract or loan file number24100.0%0——87.5%

Compared with Presidio

We ran Microsoft Presidio on the same 366 documents and scored it with the same code (lib/score.mjs): any span Presidio returns counts as a coded passage. Configuration: presidio-analyzer 2.2.358 as shipped, AnalyzerEngine with its default recognisers, spaCy 3.8.7 with en_core_web_lg 3.8.0 and fr_core_news_lg 3.8.0, each document analysed in English and in French, union of the spans, no score threshold: the most favourable setting for its recall. It ran on the same computer with sockets and DNS disabled before Presidio was imported.

Method

Limits

Reproduce it

Everything is in the public ai4x-apps repository, commit 205cbba (connector 2.28.0). The run takes about half a minute; the Presidio comparison about one minute.

git clone https://github.com/ai4xedu/ai4x-apps && cd ai4x-apps
git checkout 205cbba42de7feaa01d20430ddd6523d4f970163
cd apps/mcp-anonymiseur && npm ci
node bench/ht-bench/generer.mjs --verifier   # the documents match their seeds
npm run bench:ht:test                        # → bench/ht-bench/resultats/test/RAPPORT.md

# Optional, Presidio: a separate Python environment, installed once (the only step that uses the network)
cd bench/ht-bench/comparaison
uv venv -p 3.12 .venv && VIRTUAL_ENV=.venv uv pip install -r requirements.txt "preshed==3.0.9"
cd ../../.. && npm run bench:ht:comparer     # → bench/ht-bench/resultats/test/comparaison.md

We pin preshed to 3.0.9 because version 3.0.14, the one installed by default in October 2026, stops spaCy 3.8.7 from loading its models. It does not change any result.

Raw results: ht-bench-2.28.0.json (JSON, about 190 KB): versions, seed, fingerprint, every table on this page and the full output of both runs. Cite this file for these numbers. Each version that changes detection gets its own file, and earlier ones stay online: ht-bench-2.27.0.json.

Leak test: what the AI can still read

HT-Bench measures detection value by value. The leak test asks a different question: after Hidden Tokens has coded a folder, can the AI still read any sensitive value? We don't look at what Hidden Tokens thinks it detected. We collect everything Claude could read and search it for every real value. Run on connector 2.22.0, 24 October 2026.

Results

CategoryValuesCoded, amounts "protect"Coded, default "auto"
Names959595
Companies151515
Addresses999
Phone numbers and emails131313
IBAN and bank details999
Payment card numbers888
Identity documents (ID card, social security, passport, driving licence)101010
Company identifiers (SIRET, ICE, IF, RC, CNSS…)161616
Case references (docket, contract, claim)444
Number plates444
Spreadsheet amounts18187
Total201201 (100%)190 (94.5%)

The two columns differ only on amounts. In "auto" mode, the 11 amounts left readable were invoice lines, receivables and card-payment totals; the payroll figures were coded. That is the behaviour we chose after testing with clients: a bare invoice amount does not identify anyone, and the AI needs it to build totals and charts. If your figures are confidential, set the folder to "protect" once in the app and every number becomes a consistent placeholder, restored on your computer afterwards.

Keeping the document usable

Coding everything would be easy and useless: the AI would receive a wall of codes. So we also measure what should stay readable.

Known limits of the leak test

The harness (bench/run.mjs) and the fictional corpus (bench/corpus.mjs) are in the ai4x-apps repository. Run node bench/run.mjs for the default setting, with ANX_CHIFFRES=gabarit to protect all amounts, or with --word to feed the text documents as Word files.

On your own files, you don't need our word either: the local "What Claude saw" page re-checks every response the AI received against your key. See proof, not promises.

Frequently asked questions

Does 100.0% on HT-Bench mean Hidden Tokens never misses anything?

No. It means every direct identifier in our synthetic test documents was coded by connector 2.28.0. Real files are more varied: other layouts, OCR errors, formats we have not modelled. That is why Hidden Tokens shows a plan before coding, flags indirect identifiers, and keeps a local log of everything the AI received so you can check.

Which Presidio configuration did you compare against?

presidio-analyzer 2.2.358 as shipped: AnalyzerEngine with its default recognisers, spaCy 3.8.7 with en_core_web_lg 3.8.0 and fr_core_news_lg 3.8.0, each document analysed in English and in French, union of spans, no score threshold, offline. Presidio is a toolkit meant to be extended with custom recognisers; we measured its defaults, not what a team could build on it.

Why does the default setting leave some amounts readable?

Because an invoice total, a quantity or a rate is usually what the AI needs to work on, not a secret. Hidden Tokens classifies each numeric column by its header: payroll, revenue, results or balances are protected; ordinary amounts stay readable. The plan shows the choice for every column and you can switch any column, or the whole folder, to "protect".

Can I reproduce the benchmark?

Yes. Both benchmarks and their synthetic data are in the public ai4x-apps repository. HT-Bench regenerates its documents from fixed seeds and checks their SHA-256 fingerprint, then drives the Hidden Tokens connector through the same protocol Claude Desktop uses. The raw results of each run are published as JSON.