Logo
Sending a password to a customer

19 Oct 2026 

Sending a password to a customer

Every infrastructure team has the same small, awkward problem. An engineer finishes provisioning something, and now a password, a certificate or an SSH key has to reach someone outside the company.

The honest answer, in most organisations, is email or WhatsApp. Both work. Both also leave the credential sitting in a mailbox or a chat log, indefinitely, readable by anyone who later gains access to either. For a company whose entire proposition is that customer data stays in India, under Indian jurisdiction, a credential sitting in a WhatsApp thread is a contradiction we could not defend.

So we built a service to do it properly. This is what we learned.

Why not just use an existing tool

We looked hard at the existing options before writing anything, because building is almost always the wrong answer. There are good open-source tools in this space, and we evaluated four of them seriously.

Two things decided it.

The first was mundane. The tool that came closest put authentication against our existing identity provider behind a commercial tier, and its data residency controls did not extend to the metadata we care about most.

The second was architectural, and it is the more interesting one.

Deletion is not destruction

Every one-time secret tool promises that your secret is destroyed after it is read. Most of them mean it in the sense that a database row is deleted.

That is weaker than it sounds. A deleted row persists in the write-ahead log for a while. It persists in last night's backup for as long as you keep backups. It persists on the storage layer until those blocks are reused. If you tell a customer their credential was destroyed, and it is recoverable from a routine restore, the claim was not true.

We took a different approach. Every secret is encrypted with its own key, generated fresh by our key management system and stored only in wrapped form alongside the ciphertext. Destroying a secret means destroying the wrapped key. From that moment the ciphertext is unreadable by anyone, including us, including from a backup, because the only path back to the key is gone.

That property has a name, crypto-shredding, and it is not a new idea. What it changes is what you can honestly say to a customer, and to an auditor.

It also led us somewhere counterintuitive: the service is deliberately excluded from our backup regime. There is nothing worth restoring. A restored store contains only ciphertext whose keys no longer exist. Excluding it is a control rather than an oversight, and we document it that way.

The passphrase is part of the key

Most tools treat an optional passphrase as a gate: store a hash, compare on retrieval, serve the secret if it matches. That protects against someone who has the link, but not against someone who has the server.

We made the passphrase part of the encryption key instead, combined with the key from our key management system. There is no stored hash to compare, because there is nothing to compare against. A wrong passphrase simply produces a key that fails authentication, which is indistinguishable from the secret not existing.

The consequence is worth stating plainly: a passphrase-protected secret cannot be read by ZeaCloud. Not by an engineer with access to the server, not with full access to the key management system, not with both. The passphrase never reaches us in storable form.

This is why we insist operationally that the link and the passphrase travel by different channels. The link goes by email. The passphrase goes by voice. The technical design makes that split meaningful; the operational discipline is what makes it real.

The bug that nearly made it useless

Here is the one we would have missed if we had not thought about it early.

A one-time link that is destroyed when fetched sounds correct until you remember what happens to a URL in an email. Microsoft Defender fetches it. Proofpoint fetches it. Link preview generators fetch it. By the time a human clicks, the link has often already been retrieved several times by machines.

Burn-on-fetch would mean a meaningful proportion of our links arrived already dead, and the failure would look like our service being broken rather than like mail security doing its job.

So fetching a link reveals nothing and destroys nothing. It shows a page saying a credential is waiting, who it is from, and when it expires. Only a deliberate action retrieves it. Mail scanners can fetch the page as often as they like.

Alongside that, retrieval is a single atomic operation, so two simultaneous attempts produce exactly one plaintext rather than two. We test that with fifty concurrent requests against the same secret, repeatedly, because a race condition in exactly this place would be the worst possible bug in exactly this product.

Everything fails closed

The service cannot create or reveal a secret if the key management system is unreachable. There is no local key cache and no degraded mode. An outage means nobody can share credentials for a while, which is an inconvenience. A cache would mean keys living somewhere we did not intend, which is a breach waiting to be discovered.

We think that is the right trade, and we would rather explain an outage than a silent weakening.

What this cost, and what it bought

A few hundred lines of Go with no third-party dependencies, authentication against our own identity provider with hardware keys, malware scanning on uploads, and a full audit trail. It runs on our own infrastructure in Greater Noida. No part of a credential passes through a third party at any point.

Writing it was the easy part. The harder work was the parts around it: a threat model, dependency and static analysis in our build pipeline, a penetration test, and the operating procedure that makes the two-channel rule something people actually follow rather than something a form suggests. Custom code inside a compliance boundary carries evidence obligations that an off-the-shelf tool would have carried for you, and that cost does not shrink because the codebase is small.

We think it was worth it. Not because the idea is novel, it plainly is not, but because sovereignty is not a claim you can make at the marketing layer and abandon at the operational one. If customer data must stay in India, so must the password you use to reach it.