How Tellproof handles your data and your evidence
Tellproof is built so that the people who rely on an evidence pack (a bank, an insurer, an auditor) do not have to trust the vendor or us. This page says what leaves your environment, what never does, how a pack is protected, and where the limits are.
What leaves your environment
Your application's SDK sends spans to the Tellproof evidence agent, which runs on your own infrastructure. In local mode the agent keeps its signed batches on your machine and sends nothing. When it is connected to Tellproof, it sends one signed batch of aggregates per hour. A batch holds only counts and short names:
- Token and call counts per provider, model and region.
- How many spans carried personal data and how many of those were redacted, as counts.
- How many model calls had a guardrail decision, and how many were blocked.
- Evaluation results: suite name, model, prompt version, when it ran and its pass rate.
- Agent activity counts: runs, tool calls, tool errors, high-impact calls and how many were approved, escalations.
- Which models and prompt versions were live, when they changed, and any hour with an unusual error or block rate.
- Provider usage totals, if you turn on the read-only usage pollers.
- One Merkle root and a leaf count: a commitment to that hour's traces.
It never sends:
- Prompts, completions, messages or any span content.
- Tool or function arguments, return values or exception messages.
- Raw trace IDs. Each trace is committed as a salted hash, and the salt comes from a secret that stays in your environment.
- End-user identifiers, IP addresses or request bodies.
The full format is the published batch schema, spec/batch.schema.json, in the open-source repository.
How you can check that
- The SDKs never read content. The Python and TypeScript SDKs record provider, model, region, token counts, operation, timing and error status. They never read prompts, completions, arguments or return values, so there is nothing to filter.
- The agent drops content at parse time. If another OpenTelemetry exporter sends message attributes, the agent discards them before anything is aggregated. It only counts how many spans arrived with content.
- Dry run.
tellproof-agent --dry-runprints every batch it would send, decoded, and sends nothing. Run it against your own traffic before you connect. - Open source. The agent, the SDKs and the verifiers are published under the Apache License 2.0, and release binaries carry signed build provenance that ties them to that source.
- One destination. The agent sends batches only to the Tellproof server you configure. The only other outbound calls are the read-only Langfuse and provider usage APIs, and only if you turn them on.
How a pack is protected
- Signed. A pack is an in-toto statement in a DSSE envelope over canonical JSON (RFC 8785), signed with ECDSA P-256. The signing key is held in AWS KMS in Sydney. The private key never leaves KMS, and the service can only ask KMS to sign.
- Chained. Each pack names the digest of the previous pack for the same system, so a removed, reordered or edited pack breaks the chain.
- Committed to the traces. Each hour's traces are committed as a Merkle tree. Later, you can disclose a single trace and prove it was counted, without revealing any other.
- Published daily. Every pack digest issued each day goes into a signed, chained daily checkpoint in a public Git repository. Anyone can check which day's checkpoint first lists a pack, so a pack issued later cannot pass as an earlier one.
tellproof-verify checkpointproves a pack is in a day's checkpoint. - Keys with dates. The issuer's public keys are published at
/.well-known/jwks.jsonwith the dates each key may sign, and a list of revoked keys. A signature counts only from a key that was valid when the pack was issued and has not been revoked. - Three verifiers that agree. The command-line verifier, the browser verify page and an independent Python verifier must give the same result on every published test vector. The verify page runs every check in the reviewer's browser.
The evidence agent
- Each agent has its own Ed25519 key, generated on your machine at enrolment and stored with mode
0600in its data directory. Batches are signed with it, numbered and chained, so a lost or replayed batch is detected. - Enrolment uses a one-time token that expires after 24 hours. The server stores only its hash.
- The span receiver listens on the loopback interface by default and has no authentication. Expose it more widely only on a network you control.
- Secrets (the salt secret, Langfuse keys, provider admin keys) come only from environment variables or files with mode
0600, and are never logged. - Batches are written to a local queue and fsynced before they are acknowledged, then retried until the server accepts them.
- The container image is a static binary on a distroless base, running as a non-root user.
The Tellproof service
- Separation between customers. Every query runs in the signed-in organisation's scope, enforced by Postgres row-level security, not only by application code.
- Evidence is append-only. Database triggers refuse any change to, or deletion of, stored batches, evaluations, packs, checkpoints and verifier views.
- Sign-in is by email magic link through Supabase Auth. The service checks each access token's ES256 signature, issuer, audience and expiry itself. Sessions are HttpOnly, SameSite cookies, and every form submission must come from the app's own origin.
- The web app runs no JavaScript. Its pages forbid scripts and framing through a Content Security Policy.
- Share links. A share-link token is shown once and stored only as a hash. It travels in the URL fragment, which browsers never send to a server. Links expire and can be revoked at once. Verifier addresses are recorded only as a keyed hash that changes daily.
- Integration credentials you give us (Vanta) are encrypted with AES-256-GCM before they are stored, bound to your organisation, and never shown again.
- Logs hold identifiers and digests only, never tokens, keys, credentials or batch contents.
Where data is processed
| Provider | What for | Where |
|---|---|---|
| Supabase | Database (batches, packs, organisation data) and sign-in emails | Sydney, Australia |
| Amazon Web Services | KMS signing key | Sydney, Australia (ap-southeast-2) |
| Fly.io | Runs the Tellproof service | Sydney, Australia |
| Cloudflare Pages | Serves this site and the static verify page | Global edge network |
| GitHub | Public daily checkpoints and the open-source code | United States |
The checkpoint repository holds pack digests only: no names, no contents. Vanta receives only what you connect it to receive.
What we do not claim
- A pack shows what your telemetry shows. Calls that never reach the agent are not in it; the coverage objective compares traced tokens with your provider's billed usage to show how much is missing.
- Tellproof does not yet hold a SOC 2 report or an ISO/IEC 27001 certificate of its own, and has not yet had an independent penetration test. We will list them here when we do.
- A signature proves the pack came from Tellproof's key and has not changed since. It does not prove the telemetry your systems produced was complete or truthful.
Reporting a vulnerability
Report it privately through GitHub's private vulnerability reporting on the open-source repository (the Security tab, "Report a vulnerability"). Please do not open a public issue. We acknowledge reports within two working days. The most serious reports are any way to make a tampered, unsigned or wrongly dated pack verify, and any way the agent or an SDK could send content off your machine.