A deep-dive into Zippd's system architecture and the choices that remove categories of risk from the threat model.
Updated May 18, 2026
Most "secure" services treat privacy as a feature added to a normal architecture. Encryption gets bolted on, content scanning runs alongside, the database holds plaintext. A breach exposes everything.
Privacy-by-design flips the model. Start with the question: what can the vendor know? Build the system so the answer is "as little as possible, and never the content itself." Features that would require knowing more don't get built.
Here's how Zippd does it.
Ann Cavoukian articulated seven principles of privacy by design in the 1990s. The two that matter most for file sharing:
The deeper principle: data minimization. Don't collect what you don't need. Don't keep what you don't need. Don't even know what you don't need.
Our Laravel application handles HTTP requests. What it sees:
What it never sees: file content, file names, encryption keys. The upload flow uses presigned URLs — the browser PUTs ciphertext directly to storage. Our application server is not in the file-content data path.
Stored per file:
What's not stored: file content (lives on Wasabi), encryption keys (live only in URL fragments), plaintext IPs, plaintext filenames.
Wasabi (S3-compatible) holds ciphertext blobs. We don't put anything else there. The bucket has server-side encryption enabled as a belt-and-suspenders layer, but the real protection is client-side AES-256-GCM done by the browser before the byte reaches Wasabi.
Web server access logs contain the IP and request path for up to 30 days, then rotate out. Application-level logs contain hashed identifiers and timestamps, no plaintext content. Stack traces from errors get the same scrubbing.
The decryption key for every file:
crypto.subtle.generateKey().#k=.The key passes through:
The key does NOT pass through:
Even with the zero-knowledge architecture, multiple layers reinforce each other:
| Layer | What it protects |
|---|---|
| HTTPS in transit | Network observers |
| Wasabi server-side encryption | Stolen disks at the storage tier |
| Client-side AES-256-GCM | Vendor-side reading; main protection |
| URL fragment for keys | Key transmission to the server |
| Auto-expiry of files | Reduces the exposure window |
| IP hashing | Anonymity if logs leak |
| Sealed metadata blob | Filename privacy |
Privacy by design is a real cost. Features we deliberately don't ship:
These omissions are the cost of the privacy guarantee. They're acceptable.
Don't take our word for any of it. Check:
*.wasabisys.com, not to our backend. The request bodies are ciphertext.crypto.subtle.encrypt and trace the flow.#k=... fragment. Note that this part of the URL was never in any HTTP request.GET /api/files/{publicId}/meta returns an opaque base64 string for encrypted_meta. That's the encrypted filename. We can't read it.Honest threat enumeration:
The crypto runs in unminified JavaScript that you can audit in browser DevTools. The server code is not yet publicly published but is a fairly thin orchestration layer around standard S3 multipart operations.
Not yet by a formal third party. The model is publicly described and verifiable individually.
Public ID, storage key, ciphertext size, expiry timestamp, owner user ID (if registered), hashed IP. Nothing about the file's actual content, name, or type.
We comply with valid legal process for what we have. We have ciphertext and an opaque metadata blob. We cannot produce the file's plaintext or its key.
Upload a file with DevTools open. Walk through the architecture described here. It should match the bytes you see flowing.
A plain-English explanation of what happens when you click "encrypt." Lock-and-key analogi...
Choosing a service, configuring it right, and avoiding the common mistakes. A non-technica...
Same zero-knowledge encryption Mega is known for. No bulky desktop client. No account requ...
Send up to 20 GB encrypted in your browser. No Dropbox subscription. No account at all.