The Developer's Guide to Private File Sharing: Why "Encrypted" Doesn't Always Mean Private
When you upload a file to most services and they say "your data is encrypted," ask yourself: who holds the key?
In almost every case, the answer is the service itself. That means encryption is protecting you from third parties, but not from the platform you just uploaded to. If their database is breached, subpoenaed, or their team goes rogue, your files are accessible.
This distinction matters more than most developers realize.
Server-Side Encryption vs. Zero-Knowledge Encryption
Server-side encryption (what most services do):
Your file is encrypted at rest using a key the server generates and stores
The server can decrypt your file at any time
- TLS protects data in transit, but once the server receives it, all bets are off
Zero-knowledge encryption (what privacy-first services do):
Encryption happens in the browser before any data is sent to the server
The decryption key never reaches the server
- Even the developer cannot access your files
How Zero-Knowledge File Sharing Works
The trick is actually elegant. Using the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web\_Crypto\_API), you can do all of this in the browser:
Generate an AES-256-GCM key entirely client-side
Encrypt the file locally before upload
Upload only the ciphertext
- Embed the key in the URL fragment (the
#part of the URL)
- Embed the key in the URL fragment (the
URL fragments are never sent to the server — they are a browser-only construct. So a share link like
https://example.com/file/abc123#decryptionKeymeans the server only ever sees/file/abc123.
The recipient opens the link, the browser reads the key from
window.location.hash, decrypts the ciphertext locally, and the server was never involved in the key lifecycle.
A Practical Example: FileShot
FileShot implements exactly this model. Every file is encrypted with AES-256-GCM in the browser using the Web Crypto API before a single byte is sent to the server. The share URL contains the decryption key in the fragment.
Key properties of this design:
No key escrow — FileShot's servers hold zero keys
No plaintext ever in transit — what the server stores is computationally useless without the key
No backend changes needed — the security property is enforced by the client
- Files expire automatically — metadata deletion is clean because there's nothing sensitive server-side
The Tradeoffs
Zero-knowledge isn't free. You give up:
Password recovery — if you lose the URL with the key fragment, the file is gone
Server-side search — you can't search encrypted content
- Deduplication — identical files encrypt differently due to unique IVs
For file sharing use cases, these tradeoffs are usually worth it.
The Takeaway
The next time a service claims to be "encrypted," probe deeper. Ask: is the key ever on the server? If yes, you're trusting the platform. If no, you have real zero-knowledge privacy.
For developers building tools where user privacy matters, the Web Crypto API makes implementing true zero-knowledge architecture surprisingly straightforward.
If you're curious about the implementation details, I wrote a technical deep-dive on [Dev.to](https://dev.to/graysoftdev/how-i-built-zero-knowledge-file-sharing-using-the-web-crypto-api-no-server-ever-sees-your-data-28cp) covering the actual code.
Try it live at [FileShot.io](https://fileshot.io).