How it works
Files only you can open.
The short version
Three steps
No accounts, no tracking, no software to install.
You create a link
Your passkey creates a personal lock that only you can open, right on your device. Your link lets anyone seal a file inside that lock, and nothing but your passkey can open it again.
Anyone sends you files
They open your link and drop in a file. Their browser locks it to your public key before a single byte is uploaded. They never need an account or your email address.
Only you open them
We email you that a file arrived. You open the link, your passkey unlocks the file on your device, and it downloads. No one in between can read it.
What happens to your file
It travels locked the whole way
The only place it is ever readable is the sender's screen and yours.
Sender's browser
The file is encrypted here, on their device, before it uploads.
Lockedreceive.link
We only ever hold the locked file. We have no key, so we can't open it.
Still lockedYour device
Your passkey unlocks it here, and only here. The file is finally readable.
UnlockedWhy it's private
What we can, and can't, do
Locked before it leaves
Every file is encrypted in the sender's browser, before any of it is uploaded.
Only your passkey opens it
The key stays in your control, behind your passkey. Not on our servers, not in the link.
We never see your files
We only ever hold the locked version. Filenames included.
We don't store your email
It's sealed inside your link. We unseal it for a moment to notify you, then let it go.
Files clean themselves up
Anything sent to you auto-deletes after 7 days.
You stay in control
Disable your link whenever you want, and new files stop arriving.
For cryptographers. Everything broken down step by step.
The full round-trip
- Setup. You enter an email and create a passkey. Your browser derives your identity keypair from it (PRF → HKDF → P-256), seals your email to the server's public key with HPKE, and registers
{sealed_email, share_key, label}with the worker. Your private key is never sent. - Confirm. The worker unseals your email, holds the unsigned link in KV for an hour, and emails you a one-time confirmation link. You click it; the worker signs the link with
ECDSA P-256and hands back your permanent share link. - Share. You post the link anywhere. It carries your public key, your sealed email, and the server's signature. There is no secret inside it, so it is safe to make public.
- Send. A sender opens your link and drops a file. Their browser mints a throwaway identity, runs
HPKE Authto your public key, and AES-256-GCM-encrypts the file and its metadata in 64 KiB authenticated chunks. Encryption completes before any upload starts. - Upload. The worker verifies your link's signature and returns a presigned R2 URL (several, for multipart on large files). The sender's browser PUTs the ciphertext straight to R2 through it; the worker only signs URLs and verifies links, never handling the bytes. A Durable Object enforces exactly-once delivery.
- Notify. The worker unseals your email from the link, in memory only, sends you a delivery link to
/d/<id>, then forgets the address. The link and the stored ciphertext both expire in 7 days. - Receive. You open the delivery link. Your browser re-derives your identity from your passkey, fetches the ciphertext, and runs
HPKE SetupAuthR+ AES-256-GCM to verify and decrypt each chunk straight to disk. Only your passkey can complete this step. - Clean up. The R2 object auto-deletes on its 7-day lifecycle. You can disable the link at any time; the worker flags it in KV and refuses further uploads.
Identity
Your keys are derived deterministically from your passkey, on your device, through the WebAuthn PRF extension. None of it ever reaches our servers; your passkey itself syncs only through your platform's encrypted keychain, never through us.
The keypair is bound to the canonical RP-ID, so each identity is scoped to its namespace. The private key is reproduced from the passkey secret each session and never persisted to disk.
Cipher suite
Every file uses the same fixed cipher suite, so there's no algorithm negotiation and nothing to downgrade. It's HPKE Auth mode over DHKEM(P-256, HKDF-SHA-256), with HKDF-SHA-256 and AES-256-GCM, per RFC 9180. The implementation uses @hpke/core and @noble/curves (the latter for a Safari-compatible DeriveKeyPair), verified byte-for-byte against the spec's known-answer vectors.
File format
The filename, MIME type, and exact size live in enc_metadata, sealed with AES-256-GCM under a separate key exported from the same HPKE context. Nothing about the file travels in the clear, and every chunk is authenticated, so any tampering is caught on open.
Senders are anonymous, by construction
A sender has no passkey and no account. Their browser mints a throwaway identity for each file, deriveIdentityFromPrf(random(32)), and uses it as the HPKE Auth sender. The sender_pk embedded in the file is random noise that links to nothing and no one. We never learn who sent you a thing.
The relay
- Links are signed by the server with
ECDSA P-256. The worker verifies the signature before accepting an upload, and rejects revoked or expired links. - Your email is
HPKE-sealed to the server's public key inside the link, and unsealed only in memory, at confirm time and on each delivery. It is never written to storage. - Ciphertext is PUT to Cloudflare R2 through a presigned URL and auto-deleted on a 7-day lifecycle. A SQLite-backed Durable Object enforces exactly-once delivery.
- Revocation and abuse limits live in short-lived KV: a revoke-token map, plus per-IP and per-email-hash counters. No file bytes, names, or plaintext emails are ever stored.
Threat model and non-goals
- No forward secrecy. Your identity key is long-lived, so a compromised passkey can decrypt past and future files sent to that link.
- Not post-quantum. Sharing rides on HPKE over P-256. The separate self-encryption suite (
0x02) is symmetric-only and quantum-safe; sharing is not. - Deniable by design. We make no non-repudiation claim. A recipient can forge a file attributing any sender, and senders are ephemeral regardless, so nothing here proves who sent what.
- Observable metadata. The relay can see a ciphertext's length, its timing, and IP addresses. Length implies an approximate plaintext size.
- No escrow, no rotation. We hold zero key material. Key rotation is not in v1; you would issue a fresh link instead.
Verify it yourself
The exact byte format of an encrypted file is written down in a versioned spec, with test vectors so anyone can confirm their own implementation produces identical bytes. The browser client and the worker are open source, so you can check every claim here for yourself.
Questions
Good things to ask
Do I need an account?
No. You create a link with your passkey, and the people sending you files just open the link in their browser. No app and no sign-up, on either side.
What's a passkey?
It's the same thing your phone or laptop already uses for Face ID, a fingerprint, or your screen lock. receive.link uses it to create an encryption key that never leaves your control. There's nothing new to invent or remember.
What if I lose my passkey?
Passkeys are looked after by your device and usually synced across them, through iCloud Keychain, Google Password Manager, and the like, so they follow you to a new phone or laptop. As long as you can sign in with your passkey, you can open your files. Keep it as safe as you'd keep the keys to a mailbox.
How is this different from email or Dropbox?
Those services can read what you send through them. receive.link can't. Files are locked on the sender's device before they ever reach us, and we only ever hold the locked version.
Can you read my files?
No. We never have the key. The most we can see is the size of a locked file and when it was sent, the same way the post office can see a sealed envelope's size without opening it.
How do you email me if you don't store my address?
Your address is sealed inside your link when you create it, encrypted so that only our server can briefly open it. When a file arrives, we unseal it just long enough to send you that one notification, then drop it. It's never written to a database, so there's nothing stored to lose or leak.