Every time you share a file via Google Drive, Dropbox, or WeTransfer, you're making an implicit trust decision: I trust this server to not read my file.
For most files, that's fine. For sensitive files — contracts, credentials, medical records, source code — it's a significant risk that most developers ignore.
The Problem: Server-Side Trust
When you upload a file to a typical sharing service:
- Your file travels over HTTPS to their server
- Their server stores it (usually encrypted at rest, but they hold the key)
- They give you a share link
The server itself can read your file. So can employees with database access, law enforcement with a subpoena, and attackers who compromise their infrastructure.
What "Zero-Knowledge" Actually Means
Two conditions must both be true:
- Client-side encryption — the file is encrypted before leaving your browser
- Key never reaches the server — the decryption key is delivered out-of-band
HTTPS alone does not count — the server decrypts on arrival. Server-managed encryption does not count — they still hold the key.
The URL Fragment Solution
The hash fragment (#) part of a URL has a critical property: browsers never include it in HTTP requests. This is specified in RFC 3986.
This makes URL fragments a natural out-of-band channel for key delivery.
How FileShot.io Implements This
FileShot.io uses the Web Crypto API for AES-256-GCM encryption entirely in the browser:
// Generate 256-bit AES-GCM key
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
// Random 96-bit IV (correct for GCM)
const iv = crypto.getRandomValues(new Uint8Array(12));
// Encrypt the file buffer
const ciphertext = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
fileBuffer
);
// Export key for fragment delivery
const rawKey = await crypto.subtle.exportKey('raw', key);
const b64Key = btoa(String.fromCharCode(...new Uint8Array(rawKey)));
// Share URL: https://fileshot.io/d/FILE_ID + "#" + b64Key
The server receives only the encrypted file and a random file ID — mathematically incapable of decryption.
Practical Implications
Protected against:
- Server compromise — attacker gets ciphertext only
- Subpoenas — server has nothing to hand over
- Employee access — no plaintext stored
NOT protected against:
- Compromised browser/endpoint
- Sharing the complete URL to an untrusted party
Try It
fileshot.io — no account needed, free, no file size limit.
Self-hosted: github.com/FileShot/FileShotZKE (MIT)
Top comments (0)