How LinkPilot Secret Links work.
A plain-language reference to how secret payloads are stored, revealed, and destroyed — and what we deliberately do not do with them.
Secret Links are private by design. LinkPilot separates secret-sharing workflows from marketing-link analytics. Secret contents are never used for analytics or profiling.
Found a vulnerability or abusive link? Report it here — reports go straight to the team.
1. Overview
LinkPilot runs two distinct link pipelines on the same platform: Smart Links for branded short URLs with click analytics, and Secret Links for one-time, expiring, passphrase-protected delivery of sensitive content. They are kept apart at the data, code-path, and product level so that secret payloads can never bleed into analytics dashboards, dataset exports, or AI features.
This page describes the Secret Links pipeline specifically: how a secret is created, how it is revealed, what happens after it is viewed, and what metadata is logged along the way.
2. How Secret Links work
- The sender creates a secret with optional passphrase, expiry window, and burn-after-views limit.
- The sender's browser encrypts the payload before anything is sent. What reaches us is ciphertext, written to a dedicated
secret_linkstable, isolated from the click-analytics tables. - LinkPilot returns a short URL (e.g.
shrd.link/s/<slug>#k=<key>) to share with the recipient. The part after the#is the decryption key, and it is generated in the sender's browser and never transmitted to us. We cannot reproduce this URL later. - When the recipient opens the link, the app calls the
secret-revealedge function. AGETreturns metadata only (status, whether a passphrase is required). APOSTwith the passphrase is what returns the ciphertext. The recipient's browser then decrypts it using the key from the URL fragment; the reveal function itself never decrypts anything and could not if it wanted to. - A successful reveal is recorded atomically and may immediately mark the secret as
burned, depending on the burn-after-views setting.
3. Encryption model
We want to be precise here, because the words "encrypted" and "zero-knowledge" are often used loosely.
- In transit: all traffic is TLS-encrypted end to end between the recipient, our edge, and our managed database.
- In your browser, before transport: since 29 September 2026 the payload is encrypted client-side with AES-GCM-256 using a 256-bit key generated in your browser. We store the ciphertext and nothing else. The key travels in the fragment of the share link, after the
#, which browsers do not send to any server — not to us, and not to Cloudflare, which serves the reveal page. - At rest: the ciphertext sits in a column logically separated from analytics data, on a managed Postgres instance that also has disk-level encryption.
- Passphrases: when you set one, it is stretched with PBKDF2-SHA256 (210,000 iterations) and combined with the link key through HKDF-SHA256, so neither the link on its own nor the passphrase on its own decrypts the secret. Separately, a SHA-256 hash of the passphrase is sent so the server can refuse to return the ciphertext at all to a caller who does not know it. The plaintext passphrase is never written to our database or logs.
- What this does and does not protect: it removes us, our database and our edge from the trust boundary. It does not protect a secret whose full link has been forwarded, screenshotted, or logged by something on the recipient's side, because that link carries the key.
- The two exceptions, stated plainly: secrets created before 29 September 2026 are stored as plaintext. They are never silently rewritten, they keep working exactly as before, and they age out as they expire. File attachments are encrypted in the browser too, with a key derived from the secret's own key, so one link opens both and we hold no key for either. What we can still see is a file's name, size and type: those are metadata columns, not contents. Attachments uploaded before 29 September 2026 remain stored as plain files.
The practical consequence is worth spelling out: because we never hold the key, we cannot recover a secret for you. If the share link is lost, the contents are gone.
Verify it yourself. You do not have to take the browser-side encryption on trust. The same encryption code ships in our open-source linkpilot-cli repository (MIT licensed), which holds the CLI, the TypeScript SDK and the MCP server. The repository commits the test vectors the web app is checked against, so you can read the key derivation, run the vectors, and confirm that what leaves a client is ciphertext and that the key goes only into the link fragment. If you find a gap between that code and this page, report it.
4. What happens after a secret is viewed
- The view is recorded atomically through a database function — concurrent reveal attempts cannot leak the secret twice.
- If the view-count limit is reached, the secret's status flips to
burnedand the stored payload is overwritten with[REDACTED]. - Subsequent reveal attempts return a clear "already viewed and destroyed" response with HTTP 410.
- The audit timeline records every view, burn, and revoke event with a hashed IP — useful for incident response and credential rotation.
5. Expiration and revocation
- Every secret can carry a time-based expiry — 1 hour, 24 hours or 7 days on any plan, or a custom date and time on Pro — and an optional view-count cap.
- Expired secrets are flipped to
expiredon the next access and the payload is redacted in the same write. - The owner can revoke a secret manually at any time from the dashboard. Revoked secrets immediately refuse to reveal and return HTTP 410.
- Once a secret is burned, expired, or revoked, the payload cannot be recovered through the product — there is no "unrevoke" or "restore" action by design.
6. Passphrase protection
- Passphrases are optional but recommended for any secret you do not want a stray viewer to consume.
- The passphrase is SHA-256 hashed in the browser, sent over TLS, and compared by hash on the server. The raw value never reaches our database.
- We rate-limit passphrase attempts to 5 per IP per minute per secret, enforced across an in-memory limiter and a database-backed sliding window.
- Every failed attempt is written to the audit log with a hashed IP so workspace owners can see suspicious activity.
- We recommend sending the passphrase through a different channel from the link itself — for example, the link by email and the passphrase by Slack DM or SMS.
7. Link scanner and preview-bot protection
Email security scanners and chat-app link unfurlers (Slack, LinkedIn, iMessage, Outlook) routinely fetch URLs as soon as they appear. For a burn-after-read link, a naive design would mean the very first preview destroys the secret before the recipient sees it.
LinkPilot prevents that in three ways:
- Separate metadata and reveal endpoints. A
GETon the reveal endpoint only returns the status and whether a passphrase is required. A view is only recorded on an explicitPOSTreveal, which is the action a human takes after clicking the reveal button. - Passphrase gate. When a passphrase is set, no payload is returned to anyone — bot or human — without the correct hash.
- Cache-Control: no-store on every reveal response, so intermediaries do not cache secret contents.
8. What metadata is logged
For each reveal attempt we record only what is needed to give workspace owners a credible audit trail:
- Timestamp of the attempt.
- Hashed IP: SHA-256 of the client IP combined with a daily-rotating salt, truncated to 32 characters. The raw IP is never stored.
- Coarse geolocation (country and city) from the edge, when the upstream provides it.
- User-Agent string reported by the client.
- Event type: created, viewed, failed_passphrase, burned, expired, revoked.
We do not log: the secret contents, the raw passphrase, the raw IP address, cookies on the recipient (there are none), or any third-party tracking pixels.
9. Difference between Secret Links and analytics links
| Aspect | Smart Links (analytics) | Secret Links |
|---|---|---|
| Purpose | Branded short links with click tracking | One-time, expiring secure delivery |
| Storage | Links + click events | Ciphertext in an isolated secret_links table, redacted on destroy |
| Per-click data | Hashed IP, referrer, UA, geo, UTM | Hashed IP, UA, geo, event type — no payload |
| Analytics / AI use | Yes (aggregated, hashed) | Never — fully excluded |
| Lifetime | Persistent until you delete | Burns, expires, or revokes; payload then irrecoverable |
| Bot previews | Counted as bot, filtered from analytics | GET returns metadata only — bots cannot reveal |
The two pipelines share the same brand, dashboard, and team controls — but the data flows do not cross.
10. Attachments
- Files are encrypted in the browser with a key derived from the secret's own key, so one link opens both the text and the file.
- They are served through short-lived signed URLs behind the same passphrase, expiry and burn controls as the text.
- A file's name, size and type remain visible to us as metadata; its contents do not.
- Attachments uploaded before 29 September 2026 remain stored as plain files until they expire; they are never rewritten.
11. Retention
- A secret's payload is overwritten when it burns, expires or is revoked. There is no restore, by design, and we cannot recover it for you.
- Account data is retained while the workspace is active and for 30 days after deletion so an accidental deletion can be reversed.
- Click analytics on short links are aggregated after 90 days into anonymized counts.
- Audit timeline events keep only the hashed, salted values described in section 8; there is no raw address to retain.
12. Anonymous secrets and workspace secrets
The free secret link generator creates secrets with no account. Burn after read is always on, the expiry is 1 hour, 24 hours or 7 days, the form is protected by Turnstile against automated abuse, and the same browser-side encryption applies.
A workspace secret adds the audit timeline, revocation from the dashboard, file attachments and, on Pro, passphrases and a custom expiry date and time. The encryption model is identical in both cases.
13. Limits, stated plainly
- A forwarded link is a forwarded secret. Nothing in the design can stop a recipient passing the link on before opening it. Short expiry and a passphrase delivered by a second channel are the mitigations.
- A lost link is a lost secret. We never hold the key, so there is nothing to recover.
- The pre-29-September exception. Secrets created before that date were stored as plaintext until they expired.
- Not open source, not self-hostable. The encryption client is published with test vectors in the MIT-licensed CLI repository; the service itself is a hosted product. If self-hosting is a requirement, see the open-source alternatives.
- A view is not a person. The timeline records when and roughly from where a secret was opened, never who. If the wrong party opened it, rotate the credential.
14. Reporting a vulnerability
15. FAQ
Is the secret end-to-end encrypted?
Yes, for secrets created from 29 September 2026 onward. The payload is encrypted in your browser with AES-GCM-256 before it is sent, and the key is placed in the part of the share link after the # — a URL fragment, which browsers never transmit. We receive only ciphertext and never receive the key, so we cannot read the secret. Attached files are encrypted the same way, with a key derived from the same link. Two caveats we want to state plainly: secrets created before that date are still stored as plaintext and keep working unchanged until they expire, and a file's name, size and type are still stored in the clear even though its contents are not.
Can LinkPilot staff read my secrets?
Not for a secret encrypted in your browser: the decryption key is never sent to us, so an operator with full database access sees only ciphertext. This is also true of anyone who compromises our database or our edge. Three honest limits: a secret created before 29 September 2026 is stored as plaintext and an operator could read it while it is still active; we can still see a file's name, size and type even though we cannot read its contents; and anyone who obtains the full share link, including the part after the #, can open the secret, which is why a short expiry and burn-after-read still matter.
Does opening a link preview in Slack or email burn the secret?
No. Link unfurlers issue GET requests, which only return metadata (status, whether a passphrase is required). A view is only recorded on an explicit POST reveal — the action the human recipient takes when they click the reveal button.
What information do you log about a view?
Per view we record: timestamp, hashed IP (SHA-256 with a daily-rotating salt, truncated to 32 chars), country and city from the edge if available, and the User-Agent string. We do not log the secret contents, the raw passphrase, or the raw IP address.
Are secrets ever used to train models or for analytics?
No. Secret payloads are excluded from analytics, profiling, and any AI features. The Secret Links pipeline is separate from the Smart Links analytics pipeline.
Can I see who opened a secret?
Not who. The timeline shows when each reveal happened, the country and city the edge reports, the browser's User-Agent string and a daily-salted hash of the network address, on Pro. That is enough to confirm delivery or spot an open from the wrong place, and it is designed so it cannot be turned into an identity.
Can I self-host LinkPilot?
No. LinkPilot is a hosted service. The encryption client is published in the MIT-licensed CLI repository with test vectors so it can be audited, but the service itself is not open source. If self-hosting is a requirement, OneTimeSecret, Password Pusher, PrivateBin and Yopass are the usual choices.
What happens if someone tries to brute-force the passphrase?
Passphrase attempts are rate-limited to 5 per IP per minute per secret across two layers (in-memory and database). Failed attempts are written to the audit log with a hashed IP.