← Toate articolele
Română

How to share API keys and secrets without putting them in Slack

A teammate needs the staging DATABASE_URL. It’s 4 PM on a Friday. The default options are: DM it in Slack, email it, or paste it into a Notion page. Each one leaves the credential in a system with effectively infinite retention and an unclear set of people who can read it next year.

A better handoff is a link that points at encrypted bytes, where the server holding them can’t read the plaintext, and the file is deleted after one download. The workflow is short enough to fit in the same five minutes you’d have spent setting up a shared password manager vault.

Why Slack, email, and Notion are wrong for secrets

A secret pasted into Slack:

  • Sits in both message histories until somebody deletes it.
  • Is searchable by anyone in the channel, including people added later.
  • Shows up in the workspace data export when somebody offboards.
  • Is one misclicked channel away from being visible to the whole company.

Email is worse. A credential sent over SMTP is stored on the sending server, the recipient’s inbox, whatever archive policy the IT team configured, and any downstream backup. Rotating the key every 90 days doesn’t fix this; it means the exposure window is 90 days long, not that it stops.

Notion, Linear, and Google Docs are built around persistence. That is exactly the wrong property for a secret.

Why a secret manager isn’t always the right tool

1Password, Doppler, Vault, Infisical all solve the “many secrets, many consumers” case well. They add real overhead for the “one credential, once” case. Setting up a shared vault for a one-off transfer is rarely worth it, and most teams just skip it and fall back to Slack.

The rough split: if a credential will be read repeatedly by multiple people, put it in a manager. If it will be read once and then rotated, a one-time link is a better fit.

What “one confirmed download” actually means

The credential is encrypted in the browser before it leaves the sender’s device. The encryption key is derived from a password that the server never sees. The server stores ciphertext, a download token hash, an upload log, and nothing that can be turned into plaintext.

The server’s copy is deleted after one authenticated download. Loading the landing page doesn’t count. A download that fails before the server has sent any encrypted data rolls the burn counter back; once encrypted bytes have started leaving the server, the file counts as consumed: if the connection drops, only that same download can pick up where it stopped, for a few minutes, and otherwise the recipient needs a fresh upload. If nobody ever starts a download, a short TTL deletes the file on the clock.

The server still keeps an audit log (URL token, timestamps, hashed and encrypted IPs with their approximate location and network, user agent, byte size). That’s intentional: it’s used for abuse investigation. It doesn’t let the operator read your file.

30-second workflow

  1. Open ttl.space.
  2. Switch to Note and paste the secret; notes are one-time by default. For a .env file, drop it in and turn on Burn after reading.
  3. Copy the link and the generated password from the success page. They are two separate values.
  4. Send the link and the password over two different channels: link in Slack, password in SMS or Signal (or the reverse). A single compromised channel should not yield both.
  5. The recipient opens the link, enters the password, and gets the secret. The server deletes its copy. The link starts returning 404.
  6. You see when that happened on the success page or in My uploads; Notify me makes your browser tell you even after the tab is closed.

From a terminal it is one line: ttl send -b .env uploads the file as a one-time link and prints the link and a generated password. See the CLI guide.

At no point does the secret sit in a message history, cloud storage, or an email archive.

Why split across two channels. The link by itself is ciphertext plus a token; without the password it decrypts to nothing. Sending both in the same Slack thread defeats half the point, because compromising that thread yields both. Splitting them means an attacker has to compromise two systems within the window before the download happens.

Burn after reading vs. TTL

Burn after reading fits a handoff that will happen in the next few minutes. The first authenticated download uses the file up, even if it breaks partway: only that same download can pick up where it stopped, for a few minutes, and every other request gets a 404.

TTL fits the case where the recipient will open the file at some uncertain time later (a contractor who will read the credentials on Monday, for example). A 24-hour TTL gives them a window and bounds the exposure.

Limits

If the credential is already leaking (sitting in shell history, a CI log, or a screenshot that got auto-uploaded somewhere), rotate it first. A short-lived link stops future copies, not copies that already exist.

This is not a substitute for a secret manager at any real scale. It’s the tool for “one secret, one person, right now.” For a team sharing dozens of credentials a week, use a manager for the repeat case and use one-time links for the handoffs that don’t belong in one.

Burn after reading can also be defeated by a recipient screenshotting the decrypted contents, or pasting them into a persistent tool anyway. If the credential is that sensitive, the real answer is a short-lived OAuth token, a hardware key, or a temporary role assumption, not a link at all. For everything else (a DB password, a staging key, a one-off webhook secret), a one-time link is a reasonable default.

Publicat · Actualizat .