Security

What we hold, and what we cannot read

The secret is sealed before it reaches us — in your browser if you use the console, in your own code if you use the API. We store ciphertext and a hash of the retrieval code, so a dump of our database yields neither your secret nor a way to fetch it. Here is the whole contract, including where it stops.

AES-256-GCM
In your client, before the call
256-bit
Retrieval codes, hashed at rest
One
Retrieval succeeds, decided in a single UPDATE
One-time handoff
Retrieval link
x-tkn.com/s/#7f3a9c1e…
one read expires in 24h unread
Encrypted before it left the sender
We hold ciphertext; the key stays in the link
Waiting for the one read…
Envelope

xtkn.v1.<nonce>.<ciphertext>

Your client encrypts and sends the envelope. We check its shape, store it, and never open it.

  • AES-256-GCM, with a 96-bit nonce and a 128-bit authentication tag.
  • A 256-bit key from a CSPRNG. No password and no KDF, so there is nothing to grind.
  • Bring your own scheme instead and we store it opaque as xtkn.v1r, without inspecting the contents.
  • An envelope that is neither form is refused with a 400 rather than stored.
Console

The browser seals it before anything is sent

A secret created in the console is encrypted in the page you are looking at. Only the envelope is sent to us. The key goes into the link fragment, which a browser never transmits, so no request we receive has ever carried it.

  • Sealing is not optional. The console has no switch to send a payload readable, so no payload typed into it reaches us as plaintext.
  • Minted for a single retrieval. The console forces that rather than reading it off the form, which is what makes the promise the recipient is shown a true one.
  • The link is shown once. We cannot reissue it, because we hold no key for it.
  • Calling the API instead, you encrypt before the call and we store the envelope you send.
At rest

A database dump yields ciphertext and hashes

There is no key on our side to steal alongside it.

  • The ciphertext, which we hold no key for.
  • sha256 of the retrieval code. The code itself is returned to you once and never stored.
  • Metadata: expiry, recipient scope, read state, audit events.
  • Per-tenant isolation enforced on our side, not by a filter your client sends.
Fragment

The part after the # is never sent

In fragment-key mode the decryption key rides in the URL fragment, and browsers do not transmit a fragment. It never reaches a request.

  • Never in a path, a query string, a header or a body.
  • The retrieval page loads no analytics and no error reporting, and takes the key out of the address bar once the secret is shown.
  • The retrieval page decrypts in the browser. Close the tab and the key is gone.
Redemption

One conditional UPDATE decides the winner

Cap a secret at one read and two concurrent reads cannot both succeed. The state change and the recipient-auth gate are decided in the same statement, so nothing fits between the check and the burn.

  • Revoke before read, and an expiry on every token.
  • Recipient auth before reveal, by passphrase or an emailed 6-digit code, on Team and above.
  • Retrieval webhooks report that it was read, when, and from which IP, on Team and above.
  • Audit history with per-tier retention, CSV export on Team, streaming to a webhook or S3 on Enterprise.

Where the trust boundary actually sits

Fragment-key mode moves the trust boundary from our database to our web bundle. A recipient opening a secret runs JavaScript we serve, and if we were compromised and served key-exfiltrating code on that pageview, the fragment would not save them.

That is a smaller and more auditable surface than trusting a database and everyone with access to it. It is also not nothing, and we would rather you heard it here than worked it out later. The path that removes what remains is a CLI or SDK that decrypts locally.

Two further limits worth stating. We check that an envelope has the right shape, not that it is genuinely encrypted, so base64url of plaintext passes as xtkn.v1r. That catches an integration that forgot, not a caller who chose not to. And because we cannot read what you store, abuse reports are handled at the account level: we can suspend an account, and we cannot inspect a secret to adjudicate a complaint about it.

We cannot recover a secret for you either. No key, no copy, and no support path that ends in us reading it back. That is the cost of everything above, and it is the trade we would make again.

We hold no SOC 2, ISO 27001, HIPAA or PCI certification, and we publish no uptime figure or SLA outside an Enterprise agreement. When that changes, this page changes with it.

Check it yourself

Get a key without signing up

The sandbox endpoint returns a working API key with no signup and no inbox: 100 operations, 24 hours. Read the spec, call it, and find out whether this page is true.