The shortest version: don't paste the key into chat or email. Send a one-time link instead, and rotate any key that has already been in plaintext where it shouldn't have been. The rest of this guide is the detail: why the obvious channels fail, the exact hand-off procedure, what to do when a key leaks anyway, and the cases where a one-time link is the wrong tool.
Why chat and email fail
- Both are searchable forever. A key shared in 2023 is a key
your next incident is sourced from. Attackers who land in a
corporate chat or mailbox routinely search it for exactly the
strings API keys look like —
sk_live,AKIA,ghp_,Bearer. - Both sync everywhere. Phones, personal laptops, tablets — devices that are out of scope for your security controls and out of reach for your remote-wipe policy.
- Both get exported. Compliance reviews, legal discovery, and workspace exports all produce copies of history. Every export is another place the key lives.
- Both survive offboarding. The contractor's engagement ends; the DM thread with your Stripe key in it does not.
Putting a secret into either tool means accepting that the secret lives wherever the message ends up, for as long as anything retains it. Neither system was designed to forget.
Before you share: shrink the key
The best hand-off is one where the key being handed off barely matters. Before generating anything, apply least privilege at the source:
- Scope it. Stripe restricted keys, GitHub fine-grained personal access tokens, AWS IAM policies scoped to specific actions and resources — most serious providers let you mint a key that can do only the one thing the recipient needs.
- Prefer read-only unless writes are genuinely required.
- Set provider-side expiry where the platform supports it (GitHub fine-grained PATs, AWS temporary credentials via STS). Then even a leaked key has a shelf life independent of anything you do downstream.
- Name it after the recipient (
vendor-x-readonly) so that six months from now, revoking it is a one-look decision instead of an archaeology project.
A scoped, expiring, read-only key turns a worst-case leak from an incident into an annoyance.
The hand-off pattern
- Generate the key in the source system (AWS, Stripe, your own API) with the minimum scopes, per above.
- Paste it into a one-time secret link with burn-after-read on and an expiry of a few minutes to a few hours — just long enough for the actual hand-off, no longer.
- Add a passphrase, delivered through a different channel — link by email, passphrase by SMS or Slack DM. If either channel leaks, the attacker still has only half the puzzle. (LinkPilot hashes the passphrase in the browser with SHA-256 before it's sent; the raw passphrase never reaches the server's database or logs, and attempts are rate-limited to 5 per IP per minute.)
- Send the link.
- Confirm out-of-band that the recipient retrieved it, and check the audit timeline: one view, expected time, expected location. That's your receipt.
If the link goes unread past the expiry, revoke it and resend — don't extend, and don't reuse.
Example: passing a Stripe restricted key
# generate a restricted key with the minimum needed scopes
stripe api_keys create \
--restricted \
--display-name "vendor-x-readonly"
# pipe the resulting key into a LinkPilot secret
curl -X POST https://api.uselinkpilot.com/v1/secrets \
-H "Authorization: Bearer $LP_KEY" \
-d 'payload=sk_restricted_…' \
-d 'expires_in=3600' \
-d 'burn_after_read=true'
What the recipient experiences: opening the link shows a reveal page
— not the key. Link unfurlers and email scanners that prefetch the
URL get metadata only, because a view is recorded solely on the
explicit reveal action, never on the GET. When the recipient
clicks reveal (and enters the passphrase, if set), they see the key
exactly once. After that, the stored payload is overwritten and the
link returns HTTP 410. Even if the email forwards itself around the
company, only the first viewer could ever have read it — and the
audit trail shows you who that was.
Which channel for which hand-off
| Situation | Recommended method | Notes |
|---|---|---|
| Teammate, same room or on a call | One-time link, 5–15 min expiry | Passphrase optional — you can confirm receipt live |
| Remote teammate | One-time link + passphrase via second channel | 1-hour expiry default |
| Contractor or agency | Scoped key + one-time link + passphrase | Name the key after them; calendar the revocation for engagement end |
| Customer receiving their own key | One-time link from your app or support flow | 24-hour expiry; instruct them to store it immediately |
| CI/CD pipeline or service | Platform secret store (Actions secrets, Vault, ASM) | Never a link — machines don't do hand-offs |
| Whole team, ongoing access | Password manager vault | This is storage and access control, not a hand-off |
If a key leaks anyway: the rotation runbook
Treat any key that touched a chat message, email body, screenshot, git commit, or public paste as burned. In order:
- Issue the replacement key first, if the provider allows two active keys — this avoids downtime for legitimate consumers.
- Revoke the leaked key at the provider. This is the only step that actually ends the exposure; deleting the Slack message does not.
- Hand off the new key properly — one-time link, passphrase, short expiry, per the pattern above.
- Check the provider's usage logs for the leaked key between exposure and revocation. Unexpected calls mean this is now an incident, not a cleanup.
- Fix the source of the paste — add the secret to your
.gitignored env tooling, enable secret-scanning in your repo host, or update the runbook that told someone to DM it.
The whole loop should take minutes. If rotating a key is scary enough that people avoid it, that fragility is the real vulnerability — fix that first.
What to avoid
- Re-sending the same secret. Rotate instead. Re-sending erases the "exactly one exposure" audit story that made the one-time link worth using.
- Long expiry windows. Default to short. Most hand-offs complete in minutes; an 8-hour window is just a longer leak.
- Skipping the passphrase. It costs almost nothing and defends against accidental URL leaks — forwarded emails, screen shares, shoulder surfing on a shared screen.
- Screenshots of keys. They land in camera rolls, cloud photo sync, and image search. A screenshot is chat-paste permanence with worse searchability for you and fine searchability for OCR.
- Using the link tool as storage. The link is the courier, not the vault. The recipient should store the key in a password manager or env tooling the moment they receive it.
When a one-time link is the wrong tool
Honesty section — this pattern has edges:
- Machine-to-machine credentials belong in a secrets manager or the platform's native store, injected at deploy or runtime. A human clicking a link is not a deployment step.
- Long-lived shared credentials belong in a password manager with real access control and revocation per person.
- High-frequency rotation (keys that change hourly) should be automated end to end; humans and links shouldn't be in that loop at all.
- Secrets you cannot afford to have any third party store, even encrypted at rest — use an end-to-end encrypted tool or move the hand-off offline. LinkPilot is explicit that it does not claim E2EE; see the Security Architecture page for exactly what is and isn't protected.
For the common case — one human handing one credential to another human, once — the one-time link with a passphrase and a short expiry is the strongest simple pattern available.