EU AI Act · GDPR · self-hosted
Nothing personal leaves your network.
Sphragis is a single Go binary that sits between your apps and any OpenAI-, Anthropic-, or Gemini-compatible LLM. It strips personal data out of every request and every model response, and writes a tamper-evident, hash-chained record of every call. No SaaS in the data path. We never see your prompts.
01 Why now
The enforcement date moved.
The audit gap did not.
Evidence can't be backfilled
When a regulator, a customer or a breach response asks what you sent to a model and when, you either have a verifiable record or you don't. You cannot reconstruct it after the fact.
GDPR governs every prompt today
Personal data pasted into a third-party model is a transfer to a processor right now, independent of any AI Act timeline. Keeping it inside your trust boundary is the only durable answer.
A scrubber SaaS moves the risk
The usual fix hands your data to another processor. Sphragis inverts that: redaction and logging happen on your machine. There is no “us” in the data path.
02 How it works
Redact locally. Log immutably.
Forward only what's clean.
Parse the request
The gateway reads the request body for its wire format, OpenAI, Anthropic or Gemini, and dispatches redaction on the path.
Replace PII with stable tokens
Emails, cards, IBANs, secrets and keys become [EMAIL_1], [CARD_2] before a single byte leaves the machine.
Append to a hash-chained log
Each record stores a SHA-256 of the redacted payload, the previous hash, a sequence number and a timestamp. If the write fails, the gateway fails closed.
Forward, then prove
The redacted request goes upstream. Later, verify replays the chain and anchor timestamps the Merkle root publicly, revealing nothing.
03 Drop-in
One gateway for Claude, Codex, Gemini
and the OpenAI SDKs.
Redaction dispatches on the request path, so one process covers the major agents and SDKs unchanged. Claude is first-class: the full Anthropic Messages API runs through it. Google Gemini, Azure OpenAI and Ollama work too. A single instance auto-routes each request to the right provider, into one audit log.
| Path | Format | Used by |
|---|---|---|
/v1/messages | Anthropic Messages API | Claude Code, Claude Agent SDK |
/v1/messages/count_tokens | Anthropic token counting | Claude Code, Anthropic SDKs |
/v1/complete | Anthropic legacy completions | legacy Claude clients |
/v1/chat/completions | OpenAI chat completions | OpenAI SDKs, Cursor, LangChain, Ollama |
/v1/responses | OpenAI Responses API | Codex CLI |
/v1beta/models/*:generateContent | Google Gemini, generate and stream | Gemini SDKs, LangChain |
/openai/deployments/* | Azure OpenAI, OpenAI format | Azure OpenAI SDKs |
Azure OpenAI and Ollama speak the OpenAI format: point SPHRAGIS_UPSTREAM_BASE_URL at them and redaction applies unchanged. The full request URI, including the query string, is forwarded, so Gemini’s ?key= and Azure’s ?api-version= reach the provider.
04 What gets redacted
Personal data and secrets,
replaced before they leave.
| Kind | Token | Matcher |
|---|---|---|
[EMAIL_n] | RFC-ish address pattern | |
| Phone | [PHONE_n] | international form |
| IBAN | [IBAN_n] | country code plus check digits |
| Card | [CARD_n] | 13 to 19 digit PAN, Luhn-validated |
| SSN / IP | [SSN_n] [IP_n] | US SSN, IPv4 |
| Secret | [SECRET_n] | password / api_key / token / Bearer values |
| API key | [APIKEY_n] | Anthropic, OpenAI, AWS, GitHub, Google, Slack, Stripe, SendGrid |
| Private key / JWT | [PRIVATEKEY_n] [JWT_n] | PEM blocks, base64url triples |
| Custom names | [NAME_n] | your own term list, optional external NER |
| EU pack (opt-in) | [VAT_n] [AMKA_n] | EU VAT, Greek AMKA and tax id |
Tokens are stable within a text field: the same value always maps to the same number, so the model still reasons about “the same person” without ever seeing them.
05 Built to run
Operator-grade by default.
Redacts model output too
Responses are scanned before they reach your app, JSON and streamed SSE alike, so PII the model emits never lands in your code or logs. A value split across two stream chunks is still tokenized.
Reversible tokens, if you want them
Opt-in. With a 32-byte key, tokens are recorded in a local vault sealed with AES-256-GCM and become globally unique. sphragis reveal restores originals inside your boundary, or turn on auto-reveal to re-identify them in responses in flight, so your app sees clean text with no code changes. No key, no stored originals.
Prometheus metrics
/metrics exposes redaction counts by kind and direction, requests by route, upstream latency and audit-append failures. Plain-text exposition, zero dependencies.
Config your way
Drive it with env vars or a ~/.sphragis/sphragis.yaml file. Precedence is env > file > default, so existing env-only setups are unchanged.
Signed, verifiable releases
Every release ships with keyless cosign signatures, an SBOM per artifact, and SLSA build provenance for the binaries and the container image. Verify with cosign verify or gh attestation verify.
Read-only control panel
A self-contained page at /ui: a redaction playground that previews tokenization without logging or forwarding, plus a live audit view, chain status, Merkle root and recent requests by metadata only.
06 Optional anchoring
Prove the log existed.
Reveal nothing.
anchor verifies the log and submits only its opaque Merkle root to public OpenTimestamps calendars, writing a .ots proof next to it. Upgrade later to attach the Bitcoin attestation. Your prompts never leave your network.
07 Install
Run it on your machine
in a minute.
brew install --cask sphragis-oss/sphragis/sphragis docker run -p 8787:8787 -v sphragis:/data ghcr.io/sphragis-oss/sphragis curl -fsSL https://raw.githubusercontent.com/sphragis-oss/sphragis/main/install.sh | bash go install github.com/sphragis-oss/sphragis/cmd/sphragis@latest 08 Support
Seal of approval?
Sphragis is Apache-2.0 and built in the open. If it keeps your prompts clean, a star on GitHub helps other teams find it.