Security

    Secure Link Sharing for Developers

    A practical guide for engineering teams: when to use one-time links, how to script them, and how to integrate them into onboarding and CI.

    W. Miller · Updated · About LinkPilot

    If you're an engineer, secret-sharing usually shows up in three places: onboarding, vendor hand-off, and incident response. Here's a developer's-eye view of when to reach for a one-time link, when to skip it, and how to script it without leaking the secret into your shell history along the way. To try the mechanism first, the free one-time secret link generator needs no account.

    When a human is on at least one end of the hand-off and the value should not persist anywhere afterwards. The usual cases:

    • Onboarding a new engineer with their first set of credentials.
    • Sharing a temporary admin password during an incident.
    • Delivering a vendor or contractor token that should not live in your vault.
    • Rotating a credential where the old value should die promptly.
    • Sending a customer the [API key](/glossary#api-key "Glossary: api key") you provisioned for them.
    • Machine-to-machine secrets. CI environment variables (GitHub Actions secrets, for example), Kubernetes Secrets, and Vault dynamic credentials are the right primitive there. A link is for the human hand-off into those systems.
    • Long-lived team credentials. Those belong in a password manager.
    • Public configuration. Don't dress up non-secret config as a secret. Use a regular link.

    The dividing line: if both ends of the transfer are machines, use your platform's secret store. If at least one end is a human, a one-time link is usually the cleanest primitive.

    Situation Right primitive
    New engineer's first credentials One-time secret link
    CI pipeline needs a deploy token at runtime CI secret store / env vars
    Pod needs a database password K8s secret / external secrets operator
    Team login used daily by five people Password manager (shared vault)
    Customer needs their provisioned API key One-time secret link
    Secret needed inside a git repo Never — reference a secret store; add scanning to CI

    Scripting it

    LinkPilot has a REST API (available on paid plans). Issuing a secret from a script looks like this:

    LP_KEY=lp_live_...
    
    URL=$(curl -sS https://api.uselinkpilot.com/v1/secrets \
      -H "Authorization: Bearer $LP_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "payload": "'"$NEW_DB_PASSWORD"'",
        "expires_in": 3600,
        "burn_after_read": true,
        "passphrase": "'"$ONBOARDING_PASSPHRASE"'"
      }' | jq -r '.url')
    
    echo "Secret link: $URL"
    

    Pipe that URL into whatever delivery channel you already use — Slack DM, email, your onboarding tool's webhook.

    Keeping the payload out of the process list

    The snippet above has a classic flaw: interpolating the payload into -d puts it on curl's command line, where any local user can read it via ps while the request runs. Build the JSON with jq and feed it over stdin with curl's -d @- instead:

    set -euo pipefail
    
    jq -n --arg payload "$NEW_DB_PASSWORD" \
          --arg pass "$ONBOARDING_PASSPHRASE" \
          '{payload: $payload, expires_in: 3600,
            burn_after_read: true, passphrase: $pass}' |
    curl -sS https://api.uselinkpilot.com/v1/secrets \
      -H "Authorization: Bearer $LP_KEY" \
      -H "Content-Type: application/json" \
      -d @- | jq -r '.url'
    

    Three habits worth making reflexive:

    • Values arrive via environment variables or a secrets manager CLI — never typed into an interactive shell where they land in history.
    • The script prints the link, never the payload.
    • set -euo pipefail so a failed API call can't silently hand an empty URL to the next step.

    Onboarding template

    A pattern that works well for new engineers on day one:

    1. Onboarding script provisions accounts and pulls one-time credentials.
    2. Script creates a secret link per credential with a 4-hour expiry and a shared passphrase.
    3. Script sends an email with all the links and a Slack DM with the passphrase.
    4. Engineer opens each link, copies the credential into their password manager.
    5. Anything unread by end-of-day gets revoked and reissued at their pace.

    Why these parameters: the 4-hour expiry covers a normal first morning without leaving credentials live overnight; the passphrase travels by a second channel so a forwarded or misdelivered email is harmless; burn-after-read means the engineer's mailbox ends the day containing only dead URLs.

    Tell the new hire explicitly: "each link works once — save the value into your password manager before closing the tab." The most common onboarding failure is a recipient who reads the secret, closes the tab, and assumes they can come back later.

    A rotation runbook

    Rotating a shared database password with a contractor or teammate on the receiving end:

    1. Generate the new password and apply it in the source system (database, cloud console, wherever it's canonical).
    2. Update your own consumers first — CI vault, K8s secret, app config — so nothing breaks while the human hand-off happens.
    3. Create a one-time link for the new value: burn after read, 1-hour expiry, passphrase.
    4. Deliver link and passphrase through different channels.
    5. Verify the view event in the audit timeline. No view before expiry? Revoke and reissue — never re-send the same link.
    6. Confirm the old credential is disabled at the source.

    Each rotation gets its own link. Links are independent by design — that's a feature for delivery and a non-feature for governance, so the rotation schedule lives in your manager or runbook, not in the link tool.

    Incident response

    During an incident you often need to rotate a credential and distribute the new one to a few responders fast. Don't paste it in the incident channel — that channel is being recorded for the postmortem, and the secret will end up in the export, the retro doc, and every retention system downstream of them.

    • Rotate the credential in the source system.
    • Issue a secret link with a 30-minute expiry.
    • Drop the link in the channel; send the passphrase by DM.
    • After the incident, confirm the link is burned or revoked.

    The postmortem then contains a dead URL instead of a live admin password — and the audit trail gives the timeline reviewer an exact "credential re-issued at 14:32, read at 14:33" record for free.

    One unfurl-related note: chat clients fetch pasted URLs to render previews. A well-designed secret link survives this because the preview fetch is a GET and the reveal is an explicit POST — see link scanners and one-time secrets for the full mechanics. If you're evaluating a tool, test this before an incident, not during one.

    What does the audit trail tell you?

    Whether a secret was read, when, and roughly from where, and whether anyone tried a wrong passphrase. Every LinkPilot secret carries an event timeline: created, viewed, failed_passphrase, burned, expired, revoked. Views are recorded with a timestamp, coarse geolocation when available, the user agent, and a hashed IP (SHA-256 with a daily-rotating salt — the raw IP is never stored). In practice that gives you three answers scripts and runbooks can rely on:

    • Delivery confirmation — a viewed event means the hand-off happened.
    • Anomaly detection — a failed_passphrase burst or a view you don't recognize is your cue to rotate immediately.
    • A clean record for reviews — "delivered once, read once, burned" is a sentence auditors like.
    • They're not a vault. Nothing about a one-time link manages ongoing access, rotation schedules, or who-has-what inventories.
    • The link is the key. LinkPilot encrypts text payloads in your browser and never receives the key, but that key travels in the URL fragment — so anyone who obtains the full link can read the secret, and a lost link means the secret is unrecoverable. Attached files are encrypted the same way, though their names and sizes are not. Short expiry plus burn-after-read still matters. Update, 29 September 2026: this bullet previously read "they're not end-to-end encrypted", which was accurate until that date. Details on the security architecture page.
    • They don't fix secret sprawl in code. Keys hardcoded in repos need scanning and rotation, not a better delivery mechanism.
    • They can't protect the far end. Once a human has read the value, treat it as living wherever they put it.

    Try it free, no signup

    One-Time Secret Link Generator

    Share a password or note through a link that opens once.

    Open tool

    References

    Tools for this article

    Frequently asked questions

    LinkPilot sends a secret link that is gone after it is opened.

    Encrypted in your browser, revealed once, then destroyed. No account needed.

    Create a secret link

    Read next