Exchanging secrets without compromising them
"API keys, database access, certificates: the practices for passing secrets between teams, contractors and clients without finding them in a history three years later."
The best-exchanged secret is the one you never exchange
Every project starts with the same ritual: "can you send me the credentials?". And every team improvises an answer, often the wrong one. A password in an email, an API key in a Slack channel, a .env file as an attachment: the secret has just left every perimeter of control, forever.
Before looking for a better channel, ask the real question: does this secret need to exist in this form at all? Federated identity mechanisms (OIDC between a CI and a cloud, IAM roles, workload identities) replace the static secret with an ephemeral proof of identity. No key to transmit, no key to leak, no key to rotate. When that option exists, it wins: the rest of this article only concerns secrets that genuinely must travel between people.
The channels that disqualify themselves
Some channels are disqualified outright, no debate needed:
- email, replicated across servers nobody controls, indexed, archived, forwarded;
- team chat, whose history is readable by admins, exported during migrations, and kept long after members leave;
- tickets and shared documents, which outlive the project and resurface in a full-text search three years later;
- SMS and personal messengers, which blur private and professional perimeters.
The common trait: unmanaged persistence. An acceptable secret-exchange channel guarantees exactly the opposite, meaning end-to-end encryption and disappearance.
What works, from simplest to most tooled
For a one-off exchange, a single-use, short-lived link generated by an auditable tool does the job: the recipient opens it, the secret self-destructs. Confirm receipt through a second channel (a call, a message), which also confirms that the right person consumed the link.
For a lasting collaboration, one-off exchanges no longer suffice: you need a shared space. A team password manager with per-perimeter vaults remains the most accessible option; a centralised secrets manager (with access logging and role-based policies) becomes relevant as soon as the infrastructure justifies it. The selection criterion is the same in both cases: can you know who accessed what, and withdraw an access in one action?
The pattern is worth repeating: the notification message never contains the secret. It only says where to fetch it, with one’s own rights.
Least privilege is not paranoia, it is a budget
Every transmitted secret is a debt: someone will have to remember it, rotate it, revoke it. You reduce that debt at the source:
- secrets per environment, never the same token in staging and production;
- secrets per person or per service, never a shared "team" account nobody can account for;
- minimal scopes: a read-only key for a read-only need;
- short lifetimes by default, expiry being the best of rotations.
Git history never forgets
The most frequent leak goes through no exchange channel at all: it gets committed. A .env added "temporarily", a connection URL in a config file, a key in a test. History is an eternal, distributed memory: every clone carries a copy.
The defence is layered. A strict .gitignore on environment files. A secret scanner in pre-commit and in CI, blocking before publication. And one absolute rule the day a secret reaches history anyway: purging is never enough, the secret is considered compromised and rotated immediately. Rewriting history limits future exposure; it does not undo the leak.
The exit is part of the exchange
A secret-exchange process is judged by its offboarding. A team member leaving, an engagement ending, a contractor being terminated all trigger the same mechanics: revoke nominative accesses, rotate the shared secrets the person could read, check the log. If that list is painful to establish, secrets were distributed without being inventoried, and the inventory is precisely what a vault provides for free.
The checklist we apply
- Can this secret be replaced by an ephemeral identity? If yes, do it.
- No plaintext secret in an email, a chat, a ticket or a document.
- One-off exchange: single-use link, out-of-band notification.
- Lasting collaboration: shared vault, role-based access, logging.
- One secret per environment, per person, with minimal scope and lifetime.
- Secret scanner in pre-commit and CI.
- Secret in history = compromised secret: rotate immediately.
- Scripted offboarding: revoke, rotate, check the log.
None of this is expensive. What is expensive is the forgotten token in a Slack channel that still grants production access two years after the project ended.