Skip to content
CryptonymCryptonym home
Open source, Apache 2.0Phase 1 in progress, spec published

The privacy layer between your application and every LLM.

Cryptonym detects, classifies, and replaces sensitive data before a prompt leaves your process, then restores the original values in the response. The model does its job. It never sees who the data belongs to.

Two lines of code. No prompt rewrite, no proxy to operate, no network call in the default path.

Try
Your payload

7 spans detected

What the model receives

Nadia Haddad (tomas.novak@example.org, +971 55 000 0182) says her card 0647 5855 3500 6467 was declined. Emirates ID <<EMIRATES_ID:D7DPRPNQKDWDGRZU:KYNV>>, born 1980s. Request came from ipv4_l4d2byw5evlt.

PERSON_NAMEEMAILPHONECREDIT_CARDEMIRATES_IDDATE_OF_BIRTHIPV4
What your application gets

Rania Al-Farsi (rania.alfarsi@example.ae, +971 55 123 4567) says her card 4539 1488 0343 6467 was declined. Emirates ID 784-1990-1234567-1, born 1980s. Request came from ipv4_l4d2byw5evlt.

Contains a one-way transform, so some precision does not return

Detected spans, the policy action applied to each, and the detector confidence
EntityActionDetected byConfidence
PERSON_NAMESurrogategazetteer, context0.88
EMAILSurrogatevalidator, context0.99
PHONESurrogatevalidator, e1640.94
CREDIT_CARDFormat preservingvalidator, luhn0.98
EMIRATES_IDTokenvalidator, checksum0.99
DATE_OF_BIRTHGeneralisevalidator, context0.82
IPV4Keyed hashvalidator0.90
Browser demo

This is a faithful subset, not a mock: the token grammar, the determinism, the surrogate rules, and the referential integrity are the real ones. It leaves out everything that needs a key store or a vault, which is real HMAC keying, encryption at rest, the statistical detector, and the streaming rehydrator. Tokens render in the ASCII profile here because the monospace face on this page has no glyph for the Unicode brackets.

  • Apache 2.0
  • Rust core
  • Python and Node bindings
  • Byte-identical across languages
  • No telemetry
  • Offline by default
  • Hash-chained audit log
  • Crypto-shred erasure

The problem

Every prompt is an outbound data transfer. Most teams are not treating it as one.

These are not hypotheticals. They are the six ways production AI systems leak, in the order teams usually discover them.

The prompt is the leak

Every customer name, account number, and diagnosis in a prompt leaves your boundary in plaintext. It is retained, logged, and sometimes reviewed by humans under terms you did not write.

Tool results leak more than prompts

An agent that queries a database and pastes the row into the next turn has exfiltrated it. Most protection stops at the first user message and never looks at what tools return.

Regex redaction breaks the model

Replace every name with [REDACTED] and the model loses coreference. It cannot tell two people apart, so answer quality falls exactly when the task gets interesting.

Auditors ask questions logs cannot answer

Which fields left the building, under which rule, on which date, and who approved the exception. If the answer is a grep across application logs, the answer is no.

Residency is per endpoint, not per app

The same payload may be lawful to send to a model in your region and unlawful to send across a border. That decision belongs in policy, evaluated per call.

Injected instructions target your data

A retrieved document can instruct the model to encode and emit what it was given. If the model was given real data, the attack succeeds.

How it works

Eight stages between your process and the model.

Each one is a separate, independently testable subsystem. The order is not decorative: nothing downstream can undo a decision made upstream, which is what makes the fail-closed guarantee hold.

  1. A drop-in wrapper around your existing SDK client, or an explicit session API when you want the control. It walks nested JSON, protects leaf strings, and guarantees the document still validates against your schema. Tool arguments and tool results go through the same path as the prompt, because that is where agents actually leak.

Architecture

One line, and everything identifying stays on your side of it.

The coordination service sits outside the boundary on purpose. A component that cannot reverse anything does not need to be trusted, and a component that does not need to be trusted is not a liability when it is breached.

TrustedYour process, your keys
UntrustedEverything beyond the boundary
Outbound: transformed payload onlyInbound: rehydrated inside the boundary

Inside the boundary

Cryptonym engine

Runs in process. Detection, policy evaluation, transformation, and rehydration all happen here, with no network call in the default path.

Read the architecture as text
Your application (inside the trust boundary)
Calls the model exactly as it did before. The wrapper keeps the SDK surface identical, so no prompt, no schema, and no control flow changes.
Cryptonym engine (inside the trust boundary)
Runs in process. Detection, policy evaluation, transformation, and rehydration all happen here, with no network call in the default path.
Local vault (inside the trust boundary)
Encrypted at rest with envelope keys. Holds the mapping from token to original value. Nothing else ever holds that mapping, which is what makes crypto-shredding sufficient for erasure.
Audit log (inside the trust boundary)
Append-only and hash-chained, so tampering is detectable. Records what was decided and why, never the value that was protected.
Model provider (outside the trust boundary)
Receives the transformed payload and nothing else. Whether the provider logs it, retains it, or reviews it stops being your exposure, because there is nothing identifying in it.
Tools and retrieval (outside the trust boundary)
Tool arguments and tool results cross the same boundary and get the same treatment. This is the leak path most implementations miss entirely.
Coordination service (outside the trust boundary)
Optional, and deliberately outside the boundary. It stores keyed digests and opaque identifiers. A full database compromise reveals that some entity of some type exists, and nothing more. There is an adversarial test that tries to reverse a complete dump and has to fail.

Quickstart

Two lines to protect an existing call.

No prompt rewrite, no proxy to operate, no infrastructure change. If adoption is slower than not adopting, nobody adopts.

  1. 01

    Scan before you change anything

    Point the CLI at a repository, a log directory, or a dataset. It reports what is already exposed and where. Free, offline, and no commitment to the rest of the tool.

  2. 02

    Wrap the client

    One line. The wrapper returns an object with an identical surface, so chat, streaming, tool calls, structured outputs, embeddings, and vision inputs all keep working.

  3. 03

    Pick a policy and read the audit

    Start from a jurisdiction pack, run it in dry-run to see a decision diff, then turn it on. Every decision is recorded against a pinned policy hash so it can be replayed later.

pip
pip install cryptonym
npm
npm install @cryptonym/core
cargo
cargo add cryptonym-core

Packages are not published yet. The registry names are reserved and phase 2 ships the first alpha. The commands above are what the interface will be, not what you can run today.

from openai import OpenAIimport cryptonym client = cryptonym.wrap(OpenAI()) # Nothing below this line changes.response = client.chat.completions.create(    model="gpt-4o",    messages=[{        "role": "user",        "content": "Draft a reply to rania.alfarsi@example.ae about card 4539 1488 0343 6467",    }],) print(response.choices[0].message.content)

Transforms

Seven actions. Policy picks one per entity class.

Surrogate is the default because it is the only action that protects the value and keeps the model able to reason about it. The others exist because sometimes that trade is wrong.

Surrogate

The default. Use it unless you have a reason not to.

Reversible
InRania Al-Farsi
OutLayla Mansour

Type correct, locale correct, and stable per subject. An Arabic name maps to another Arabic name, never to a default Anglophone one. Substitutes are drawn from standards-reserved ranges so a surrogate can never collide with a real person.

Token

Audit-heavy contexts where the reader must see that a value was protected.

Reversible
In784-1990-1234567-1
Out<<EMIRATES_ID:K3RJ5X7QW2M4T8ZB:H4QD>>

The checksum is keyed to your tenant, so a model cannot fabricate a token that resolves and a mutated token fails closed. Two profiles ship: a Unicode one using U+27E6 and U+27E7, and the ASCII one shown here for transports and fonts that mangle those brackets. This page uses the ASCII profile because the monospace face it sets has no glyph for them.

Format preserving

The downstream format must stay valid, for example a card or an account number.

Reversible
In4539 1488 0343 6467
Out4024 0071 5588 6467

FF3-1. The output passes the same checksum as the input and can keep a revealed suffix such as the last four digits, so a validation step downstream still succeeds.

Generalise

Quasi-identifiers: ages, dates, locations, rare job titles.

One way
In1987-03-14
Out1980s

Reduces precision rather than identity. This is the honest answer to combinations that identify a person even when every direct identifier is gone. It costs the model information, which is the trade.

Keyed hash

You need to join or correlate records without carrying identity.

One way
Inacct-99182
Outacct_7f3ba91e2c40

Truncated HMAC under a tenant key. The same input gives the same digest inside a tenant and a different one across tenants, so correlation works where it should and stops where it should not.

Drop

The span carries no analytical value at all.

One way
InSent from my phone, +971 55 123 4567
OutSent from my phone,

Removes the span entirely. Cheapest to reason about and the most destructive, so it is rarely the right default.

Block

Credentials, and transfers a jurisdiction does not permit.

Refuses
Insk-live-4eC39HqLyjWDarjtT1zdp7dc
OutRequest refused: PRIVATE_KEY -> block

The request never leaves. The error names the rule that fired and what your options are, because a bare exception at three in the morning helps nobody.

Policy engine

The rules are a file, not a support ticket.

Declarative, versioned, diffable, signable, and hashed into every audit record so any past decision can be replayed against the exact rules that produced it. Unknown entity classes are blocked, not allowed.

Change a rule, watch the payload change

Outbound payload

Nadia Haddad, tomas.novak@example.org, Emirates ID <<EMIRATES_ID:D7DPRPNQKDWDGRZU:KYNV>>, card 0647 5855 3500 6467, born 1980s, from ipv4_l4d2byw5evlt.

policies/gcc-banking-strict.yaml
version: 1name: gcc-banking-strictmetadata:  jurisdictions: [UAE_PDPL, DIFC_DPL, GDPR]  frameworks: [PCI_DSS_4, ISO_27701] defaults:  action: block                  # unknown classes are blocked, never allowed  unknown_confidence_below: 0.85  on_error: block rules:  - entity: EMAIL    action: surrogate    preserve: [domain]           # keep the signal, drop the identity  - entity: CREDIT_CARD    action: fpe                  # stays checksum valid downstream    reveal: last4  - entity: EMIRATES_ID    action: token    audit: elevated  - entity: PRIVATE_KEY    action: block    reason: "credentials must never transit a model boundary" scopes:  - match: {endpoint: "api.openai.com", data_residency: US}    override:      - entity: NATIONAL_ID        action: block            # cross-border transfer not permitted  - match: {model: "llama-3.3-70b", endpoint: "local"}    override:      - entity: EMAIL        action: allow            # stays inside the boundary egress:  scan_outbound: true            # verify nothing survived masking  on_residual: blockingress:  scan_model_output: true        # catch PII the model itself produced  on_generated_pii: flag

Direct identifiers pseudonymised, quasi-identifiers generalised, transfers outside the region blocked.

  • EMAILsurrogatedomain preserved
  • PERSON_NAMEsurrogate
  • DATE_OF_BIRTHgeneraliseto year
  • IPV4hash
  • NATIONAL_IDblockcross-border

Jurisdiction packs are engineering defaults written by engineers. They are a starting point for your own review, not legal advice, and they have not been reviewed by counsel in every jurisdiction they name.

Security

Every guarantee names the test that proves it.

A mitigation without a test is a claim. These are the invariants the build refuses to ship without, each one wired to an executable check rather than a paragraph.

Fail closed, with no exceptions you did not write

If detection, policy evaluation, or the vault is unavailable or ambiguous, the request is blocked. There is no degrade-to-pass-through path anywhere in the engine.

Fault injection per subsystem asserts a blocked outcome

No plaintext leaves the boundary

Not in requests, logs, traces, metrics, error messages, or crash dumps. Redaction happens at the logging sink, so a new log statement cannot leak by omission.

Capturing subscriber test over a poisoned input

Offline by default, no telemetry ever

The default path opens no socket. Detection runs locally. There is no phone-home, and enabling any reporting is explicit and prints a notice the first time.

Full pipeline runs under a network-deny sandbox

The coordination server cannot reverse anything

The optional service stores keyed digests and opaque identifiers. A full database compromise reveals that some entity of some type exists, and nothing more.

Adversarial test attempts reversal from a full dump

Deleting one key shreds one data subject

Erasure is a key destruction, not a rewrite of an append-only store. Per-record keys under a tenant key under a root key you hold.

Shred test asserts the subject is unrecoverable

Invented tokens never resolve

The token checksum is keyed to your tenant. A model that fabricates, mutates, or replays a token from another tenant produces something that fails verification and is flagged.

Every byte of the token body is mutated and rejected

What is still exposed

The residual risk column is the reason to trust the other two. A privacy tool that publishes only its strengths is telling you which page of the threat model it hopes you will not read.

ThreatMitigationResidual risk
Detector misses a direct identifierLayered detection, then egress verification that re-scans the outbound payload and blocks.A systematic blind spot is inherited by the egress check. Material for entity classes not in the benchmark.
Quasi-identifiers still single someone outQuasi-identifier detection, population uniqueness scoring, generalisation, and a k-threshold that blocks.High and irreducible. The scorer estimates; it does not prove. A better auxiliary dataset beats it.
Prompt injection tries to exfiltrate valuesTokens carry no information, unissued tokens never resolve, encoded-token detection, ingress scanning.The entity class of a token is visible to the model by design. An opaque profile trades quality for that.
Vault theftEnvelope encryption, root key in the OS keystore or an HSM, ciphertext bound to tenant and policy version.A vault stolen with an unlocked root key is fully reversible. Key custody is yours.
Insider disables protectionThe escape hatch is per call, rate limited, emits an elevated audit event, and can be forbidden by policy.A fully privileged insider can bypass the library entirely. It is not a defence against one.

Performance

The numbers a release has to hit before it ships.

Stated as gates rather than as results, because the public benchmark is phase 4 work and has not run yet. When it does, the methodology and the corpus go out with the numbers.

Latency and cost

< 3 ms
Median added latency
per KiB of text, single threaded
< 12 ms
p99 added latency
per KiB, deterministic path
< 2%
Task quality delta
surrogate mode against unprotected baseline
0
Network calls
in the default path

Detection gates, per entity class

  • Direct identifier recall0.98
  • Quasi-identifier recall0.92
  • Precision, all classes0.97

Reported per entity class rather than as an aggregate. An aggregate hides the class you happen to care about behind the ones that are easy.

These are the engineering targets that gate a release, measured per entity class rather than as an aggregate, on the project benchmark. They are not yet published results: phase 4 builds the public corpus and the leaderboard, and the numbers will be posted with their methodology whether or not they flatter us. Enabling the NER layer or the local model assist changes the latency figures by an order of magnitude, and that will be reported separately. See the roadmap.

Alternatives

What the other approaches actually give you.

Categories rather than product names, because the useful question is not which vendor wins a matrix, it is which of these you already have and what it leaves uncovered.

Capability comparison between Cryptonym and four other approaches to protecting data sent to language models
CapabilityCryptonymRegex redactionEnterprise DLPPrompt instructionsManual review
Model receives no identifying dataYesYesPartialNoYes
Original values restored in the responseYesNoNoNoNo
Coreference survives maskingYesNoNoNoPartial
Checksum-validated detectionYesNoYesNoPartial
Covers tool arguments and tool resultsYesNoPartialNoNo
Streaming safeYesNoPartialNoNo
Deterministic and reproducibleYesYesNoNoNo
Hash-chained audit trailYesNoYesNoPartial
Fails closed on errorYesNoPartialNoNo
Runs offline with no network callYesYesNoYesYes
Scales past a pilotYesPartialYesYesNo
Covered Partly, or with caveats Not covered

Where it fits

Regulated work, and the agent systems that quietly leak the most.

The pattern is the same everywhere: the model is useful, the data is not yours to hand over, and the gap between those two facts is where this sits.

Healthcare

Summarise clinical notes and triage referrals without sending a patient identity to a model.

  • PERSON_NAME
  • MRN
  • DATE_OF_BIRTH
  • ICD10
  • NPI

Financial services

Dispute handling and fraud narratives where card numbers must stay format valid downstream.

  • CREDIT_CARD
  • IBAN
  • SWIFT_BIC
  • PERSON_NAME

Government and public sector

Case work assistants under residency rules that differ per endpoint and per record.

  • NATIONAL_ID
  • PASSPORT
  • ADDRESS
  • PHONE

Legal

Discovery review and contract summarisation across documents with privileged party names.

  • PERSON_NAME
  • ORG
  • MATTER_REF
  • EMAIL

AI agents and RAG

Protect tool arguments and retrieved chunks, which is where agent systems actually leak.

  • EMAIL
  • PHONE
  • ACCOUNT_REF
  • API_KEY

Internal developer AI

Log analysis and incident copilots that would otherwise paste production data into a prompt.

  • IPV4
  • API_KEY
  • JWT
  • EMAIL

Open source

A default has to be inspectable, or it is just a vendor you have not audited yet.

The specification is versioned separately from the implementation so a third party can build a compatible engine and prove it with the shared conformance suite. The threat model, the decision records, and the limitations page are all in the repository, and the limitations page is the one worth reading first.

Licence
Apache 2.0 with DCO
Engine
Rust, one source of truth
Bindings
Python, Node, WASM
Conformance
Shared JSON vectors
Disclosure
90-day coordinated window
Governance
Multi-organisation, planned
Seven phases, 78 pull requests, all public

Pricing

The engine is free, and it is the whole engine.

No security feature sits behind a paywall. Paid tiers exist for what genuinely costs money to run: coordination across machines, managed keys, and the evidence pack an auditor asks for.

Open source

The whole engine. Not a crippled tier.

Free
Apache 2.0, forever
  • Full detection, policy, and transform pipeline
  • Local encrypted vault and crypto-shred
  • Python, Node, and Rust packages
  • Hash-chained audit log
  • Streaming rehydration
  • Community support on GitHub
Most requested

Cloud

For teams that need shared token consistency across machines.

Usage based
when the coordination service ships
  • Everything in open source
  • Coordination service, keyed digests only
  • Policy distribution with signature verification
  • Managed key rotation
  • Aggregate non-identifying metrics
  • Business-hours support

Enterprise

Regulated deployments that have to show their work.

Contact us
annual
  • Everything in Cloud
  • HSM, KMS, and HashiCorp Vault root keys
  • Jurisdiction policy packs and review
  • Compliance evidence pack and control mapping
  • Air-gapped install path
  • Security review and named contact

Cloud and Enterprise are not purchasable yet. The coordination service is phase 5 work, and this page will say so until the day it ships.

Questions

The objections a reviewer raises.

Answered as they would be in a security review, including where the answer is no.

Does this make my processing anonymous under GDPR?

No, and anyone who tells you otherwise is selling something. Pseudonymised data is still personal data. Cryptonym is a technical and organisational measure that sharply reduces exposure at one specific boundary. It is not an exit from the regulation, and the documentation says so on its own dedicated page.

What happens to answer quality?

In surrogate mode the target is under two percent degradation against an unprotected baseline, because the model still sees a coherent, type-correct, locale-correct world where the same person is the same person throughout. Token mode is more visible to the model and costs more. Generalising a quasi-identifier genuinely removes information, and no transform can give that back.

Where does detection run?

On your machine. Deterministic validators and the local NER model both run in process. The optional language model assist runs through llama.cpp or Ollama, locally. Routing detection to a remote model would defeat the entire point, so the engine has no code path that does it.

What if the detector misses something?

The outbound payload is re-scanned after transformation, and a surviving high-confidence identifier blocks the request. That converts a silent miss into a visible failure. It is not a complete answer: the egress check uses the same detector, so a systematic blind spot is inherited. That limitation is documented rather than glossed over.

Can the model be tricked into revealing the original value?

The model never receives it. A token carries no information about what it stands for, and the mapping exists only in your local vault. A token the model invents does not verify, because the checksum is keyed to your tenant, and an unverified token is never resolved. What the model can still reveal is that a value of a given class was present.

How do Python and Node stay identical?

There is one engine, written in Rust. Both packages are thin bindings over it, and a shared JSON conformance suite runs against the built artefacts, not the source tree. Byte-identical output for the same input, key, and policy is a blocking CI gate rather than an aspiration.

What about applications we cannot modify?

An egress proxy with a generated development CA for local work, and a sidecar for Kubernetes. There is also an MCP server and an MCP proxy, which matters because tool results are the most common leak path in agent systems and most vendors ignore them entirely.

How do we erase one person's data?

Destroy that subject's key. The records become unrecoverable ciphertext, which satisfies erasure without rewriting an append-only store. One caveat worth checking in your own deployment: if your key store keeps snapshots, backups, or a soft delete, the data is not actually shredded.

Is any of this ready today?

Not yet. The specification, the threat model, and the roadmap are public and ahead of the implementation on purpose. Phase one is in progress and the repository states honestly what is built and what is not. If you need this in production this quarter, talk to us before you plan around it.

Build AI features without handing over the people behind the data.

Start with the free scanner to see what your codebase and logs are already exposing. Adopt the broker when you are ready. The whole engine is Apache 2.0.