Can ckrets read my secrets?
With client-side encryption, we can't read your secrets: we store ciphertext, and the key goes from you to your recipient, not to us. Without it, values are encrypted at rest and deleted at their last allowed reveal (one, unless you set more), a revoke or expiry, but our service can read them while they wait. Here's exactly which, and how to check.
Today, by default, our service can read what you send. A value sent with curl or any HTTP client is readable by ckrets unless you encrypt it yourself first, with the client-side encryption format. So is a value sent through our hosted MCP server. The helper and SDKs in the ckrets repo encrypt by default, but their packages are not published yet (planned).
You can see which, every time. Every create's answer carries Ckrets-Encryption: client or Ckrets-Encryption: server (server means ckrets could read it), and every signed receipt records the same as its ce claim. A key can also refuse to send anything readable: turn on clientEncryptionRequired and plain values get 400 plaintext-refused.
Each mode, plainly
| How you send it | Can ckrets read the value? Today | Planned |
|---|---|---|
Client-side encryption, key in the link (clientEncrypted, fragment.v1) | No. You encrypt before sending. The key goes after the # in the link, which browsers never send to a server. We store ciphertext. The answer says Ckrets-Encryption: client. | The published SDKs, helper and MCP helper do this by default (planned: the code is in the ckrets repo, packages not yet published). |
Client-side encryption, key wrapped to the recipient's public key (hpke.v1) | No. The key is sealed to the recipient's X25519 public key, and only their private key opens it. | The default in our published clients when the recipient is a public key (planned). |
Client-side encryption with a passphrase (pass.v1) | No, as long as the passphrase never reaches us. The key is derived from the passphrase on your side (Argon2id). Don't also put it in the passphrase field: that field is sent to us. | — |
| Not client-encrypted (today's API default, and the opt-out in our clients) | Yes, our service can. We encrypt it with AES-256-GCM under a key for your account, held in AWS's key service, and we have to decrypt it to hand it over. The answer says Ckrets-Encryption: server, and the receipt's ce is false. A key with clientEncryptionRequired refuses these (400 plaintext-refused). | — |
Not client-encrypted, with the passphrase field | Yes, our service can. The passphrase is a lock on the reveal, with counted attempts, not extra encryption. | Our clients will pair it with a key in the link, so the link and the passphrase are two separate factors (planned). |
The request page (/q/), where a person types an answer for an agent | It depends on the agent. If the request carries the agent's public key (encJwk), the page encrypts the answer in the person's browser before it is sent, and we can't read it. Without one, the answer reaches our server over TLS and is encrypted there, and our service can read it. The page tells the person which: "encrypted: in this browser, before it is sent" or "by ckrets, when it arrives". Either way, only the asking key may reveal it. | Our published helper will send a public key with every request (planned). |
Our hosted MCP server (https://ckrets.ai/mcp, create_secret) | Yes, our service can. The value arrives at our server as a tool argument. A key with clientEncryptionRequired refuses it. | The local MCP helper (npx @ckrets/mcp), which encrypts on your machine, once it is published (planned). |
In every mode, we keep metadata: who created the secret, when, its size, its policy, and when and by whom it was revealed. See What we keep.
Check it yourself
- Encrypt with your own code. The client-side encryption page has a ten-line Python recipe that needs only AES-256-GCM. Encrypt locally, send the ciphertext, and reveal it back through the API: you get back exactly what you sent, and we never had the key.
- Read the answer and the status. Every create's answer carries
Ckrets-Encryption: clientorserver, and every secret's status says whether it wasclientEncrypted. - Read the receipt. Every signed receipt records whether the value arrived client-encrypted (its
ceclaim), so you can check afterwards, offline, against our published signing key, which values we could have read. - Make it a rule.
PATCH /v1/me/keywith{"clientEncryptionRequired": true}makes that key refuse every value ckrets could read: plain creates, hosted MCP creates, and request answers the page would send in the clear. It takes effect everywhere within seconds and cannot be turned off; mint a new key to be without it. We can check that a value is in the client-encrypted format, not that its bytes are really encrypted: that part stays on your side. - Look at what the reveal page loads. Its content security policy allows scripts from our own origin only. It loads nothing from other sites.
Objections, answered
“You could be hacked.”
Yes, like any service. What matters is what an attacker gets. With client-side encryption: ciphertext and no key. A stolen copy of our database alone: ciphertext either way, because the keys live in AWS's key service (hardware certified by AWS to FIPS 140-3 Level 3), not in the database. Someone who took over our running service could read values that aren't client-encrypted while they wait to be revealed. That's why we recommend client-side encryption, and why secrets are short-lived: one reveal by default, a 7-day default expiry, and deleted at once on reveal. Proof: What we keep, client-side encryption.
“An employee could look.”
Nobody can decrypt by hand: the key policies let only the service's own role decrypt, and the people who manage the keys can't use them. But our administrators can change those policies or deploy new code, and a change like that could expose values that aren't client-encrypted. AWS logs those changes, in our account, which you can't see today. With client-side encryption, an administrator has nothing to read. Planned: alerts on key-policy changes and code deploys, and a public log of production deploys (proposed). Proof: the format page: encrypt with your own code and our people are out of the picture.
“A government could compel you.”
We would have to hand over what we hold. For client-encrypted values, that's ciphertext we can't open. For revealed, revoked or expired values, there's nothing: the value is deleted, and backups clear within 7 days. For a value that isn't client-encrypted and is still waiting to be revealed, we could be ordered to produce it. Metadata is kept for 13 months; the access record (IP address, browser, passkey id) for 30 days. We run on AWS in the United States (us-east-2). Proof: Privacy, "Requests from authorities".
“You could change the code.”
True of any service that runs code for you, including the page that opens a key-in-the-link URL in your browser. You don't have to run our code: the format is published, so you can encrypt and decrypt with your own and reveal through the API, where a change on our side can't reach your plaintext. Our reveal page loads nothing from other sites, and it removes the key from the address bar after reading it. Planned: our clients published as open source, with signed builds you can trace back to the source. Either way, the Ckrets-Encryption label and the receipt's ce claim show, for each value, whether our code ever had it in readable form. Proof: the format page and its recipe.
“What if you shut down?”
Secrets here are hand-offs, not a vault. They expire (7 days by default) and are deleted on reveal, so little is ever waiting. A client-encrypted value opens with your key, not ours. Keep your own original: we're the courier, not the archive. Planned: a published wind-down promise before 1.0 (stop new creates, let open secrets run to expiry, then delete the keys). Proof: What we keep.
What client-side encryption doesn't cover
- Metadata, as above.
- The page that opens a link. A key-in-the-link URL opened in a browser is decrypted by our reveal page, so you're trusting the page we serve. To trust none of our code, reveal through the API and decrypt with your own.
- Where the link goes. Anyone with the whole link can open it, so send it the way you'd send the secret itself. Opening the link doesn't spend the reveal (a click does), so a chat app's link preview won't burn it.
- A lost key. We can't recover a value whose key you lost. That's the point.
- What we can check. The API can check that a value is in the client-encrypted format. It can't check that the bytes are really encrypted. That part stays on your side.
What protects a value that isn't client-encrypted
- It doesn't last long. A revoke or the last reveal deletes it at once. An unrevealed value expires (7 days by default). Copies leave our backups within 7 days.
- The keys aren't in the database. Each account's data key is wrapped by a root key in AWS Key Management Service.
- Nobody decrypts by hand. Only the service's own role can decrypt.
- Our logs hold no values. No value, key, token, passphrase or
Authorizationheader is logged, and the edge keeps no access log.
What we're building next
Planned. None of these is live yet. Each will move up into the table above when it ships, with a note in the changelog.
- Published clients that encrypt by default. The helper, the SDKs and the local MCP helper already encrypt by default in the ckrets repo; their packages are not published yet. Once they are, open source with signed builds.
- The passphrase paired with a key in the link in our clients, so the link and the passphrase are two separate factors.
- A wind-down promise before 1.0.
- Proposed: alerts on key-policy changes and production deploys, and a public log of deploys.
Shipped in this release: the Ckrets-Encryption label on every create, the ce claim in every receipt, the clientEncryptionRequired key setting, and browser-side encryption on the request page when the asking agent sends its public key.
Straight answers
- Is ckrets "zero-knowledge"? We don't use the word. With client-side encryption we can't read the value. We always see metadata, and without client-side encryption our service can read the value.
- Is it end-to-end encrypted? With client-side encryption, yes, between you and your recipient. Without it, it's encrypted in transit (TLS 1.3) and at rest.
- Are you certified? Not yet; there is no official HIPAA certification. ckrets is built to HIPAA's Security Rule safeguards: encryption at rest and in transit, access control, audit records and deletion. Health data needs a business associate agreement with our health tier, available in early 2027 (planned). PCI DSS validation is upcoming; our team has more than a decade of experience running PCI-scoped systems.
Questions or a security report: POST /v1/report until a contact address is published (planned).