How We Built a Zero-Knowledge Secret Sharing Tool with Cloudflare in 5 Days

In an age where digital privacy feels like a relic of the past, we embarked on an ambitious mission: build a secret sharing platform that could guarantee complete anonymity and zero-knowledge security in just five days. The challenge wasn't just technical—it was philosophical. How do you create a service that helps people share sensitive information while ensuring that the service itself becomes a digital black hole, incapable of retaining or accessing any user data? This is the behind-the-scenes story of VanishingVault's creation, a technical sprint that proved privacy-first architecture isn't just possible, it's practical. Using Cloudflare's edge infrastructure, we built a system where secrets truly vanish, leaving no trace of their existence once viewed.
Technical Implementation
When we began architecting our zero-knowledge secret sharing platform, we faced a fundamental challenge that has plagued security engineers for decades: how do you build a system that's simultaneously ultra-secure and lightning-fast? Traditional approaches force you to choose between security and performance, but we refused to accept this compromise. After evaluating dozens of cloud platforms and architectural patterns, we discovered that Cloudflare's edge computing infrastructure offered something unique—the ability to process sensitive data at the network edge while maintaining enterprise-grade security guarantees.
The decision to build on Cloudflare Workers wasn't just about technical capabilities; it was about reimagining what's possible when you distribute security processing across a global network. Instead of funneling all traffic through centralized data centers, we could encrypt and decrypt secrets at locations just milliseconds away from our users. This edge-first approach meant that a secret shared in Tokyo would be processed by infrastructure in Asia, while a secret shared in London would be handled by European servers, dramatically reducing latency while maintaining the same security standards globally.
Architecture Overview
Our architecture embodies a radical departure from traditional web application design. Instead of the typical three-tier architecture with presentation, application, and database layers, we created a two-tier system where security operations happen exclusively on the client side. The frontend, built with Next.js and powered by the Web Crypto API, handles all encryption and decryption operations within the user's browser. This means that sensitive data is transformed into cryptographic ciphertext before it ever leaves the user's device.
The backend component—a lightweight Cloudflare Worker—serves as nothing more than an encrypted data courier. It receives opaque, encrypted blobs from clients and stores them in Cloudflare's KV storage system without any ability to decrypt or inspect the contents. This architectural decision creates a perfect security boundary: even if our entire backend infrastructure were compromised, attackers would find only meaningless encrypted data with no way to derive the original secrets.
This zero-knowledge approach represents more than just a security feature—it's a fundamental philosophical stance about data ownership and privacy. By ensuring that decryption keys never touch our servers, we've created a system where users maintain complete control over their sensitive information, even while leveraging our global infrastructure for storage and delivery.
Backend Implementation with Cloudflare Workers
Let's look at how we implemented the core functionality in our Cloudflare Worker:
// Store endpoint - saves an encrypted secret
async function handleStore(request) {
const { encryptedData, expiresAt } = await request.json();
// Generate a random ID for the secret
const id = crypto.randomUUID();
// Store the encrypted data in KV with TTL
await SECRETS_STORE.put(
id,
JSON.stringify({ encryptedData }),
{ expirationTtl: 604800 } // 7 days in seconds
);
return new Response(
JSON.stringify({ id }),
{ headers: { 'Content-Type': 'application/json' } }
);
}
// Retrieve endpoint - gets and deletes a secret (one-time access)
async function handleRetrieve(request, id) {
// Get the secret from KV
const secretData = await SECRETS_STORE.get(id);
if (!secretData) {
return new Response(
JSON.stringify({ error: 'Secret not found or already viewed' }),
{ status: 404, headers: { 'Content-Type': 'application/json' } }
);
}
// Delete the secret immediately (one-time access)
await SECRETS_STORE.delete(id);
return new Response(
secretData,
{ headers: { 'Content-Type': 'application/json' } }
);
}
Frontend Encryption with Web Crypto API
On the frontend, we use the Web Crypto API to handle encryption and decryption:
// Generate a random encryption key
async function generateEncryptionKey() {
return window.crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
}
// Encrypt data with the generated key
async function encryptData(key, data) {
// Create a random initialization vector
const iv = window.crypto.getRandomValues(new Uint8Array(12));
// Encode the data as UTF-8
const encodedData = new TextEncoder().encode(data);
// Encrypt the data
const encryptedBuffer = await window.crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
key,
encodedData
);
// Convert the encrypted data and IV to base64
const encryptedData = bufferToBase64(encryptedBuffer);
const ivBase64 = bufferToBase64(iv);
return { encryptedData, iv: ivBase64 };
}
// Decrypt data with the provided key
async function decryptData(key, encryptedData, iv) {
// Convert base64 back to ArrayBuffer
const encryptedBuffer = base64ToBuffer(encryptedData);
const ivBuffer = base64ToBuffer(iv);
// Decrypt the data
const decryptedBuffer = await window.crypto.subtle.decrypt(
{ name: "AES-GCM", iv: ivBuffer },
key,
encryptedBuffer
);
// Decode the decrypted data as UTF-8
return new TextDecoder().decode(decryptedBuffer);
}
Secret URL Generation
When a user creates a secret, we:
- Generate a random encryption key
- Encrypt the secret with this key
- Send the encrypted data to the server
- Receive a unique ID from the server
- Create a URL with the ID and the encryption key as a fragment
The encryption key is never sent to the server. Instead, it's added as a URL fragment (the part after the # symbol), which stays in the browser and isn't sent in HTTP requests.
// Create a secret URL
async function createSecretUrl(secret) {
// Generate a random encryption key
const key = await generateEncryptionKey();
// Export the key to raw format
const rawKey = await window.crypto.subtle.exportKey("raw", key);
// Convert the key to base64
const keyBase64 = bufferToBase64(rawKey);
// Encrypt the secret
const { encryptedData, iv } = await encryptData(key, secret);
// Send the encrypted data to the server
const response = await fetch('/api/store', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ encryptedData, iv })
});
const { id } = await response.json();
// Create the secret URL with the key as a fragment
return `${window.location.origin}/s/${id}#k=${keyBase64}`;
}
Privacy Benefits of Our Approach
Complete Privacy
Our zero-knowledge architecture ensures that even we cannot access your personal data.
Quick Implementation
The Cloudflare stack allowed us to deploy a privacy-focused solution in just 5 days.
No Data Retention
Secrets automatically vanish after being viewed, leaving no digital trail.
Deployment Process
Deploying our solution to production was straightforward thanks to Cloudflare's developer-friendly tools:
1. Setting Up the KV Namespace
# Create a KV namespace for secrets
wrangler kv:namespace create "SECRETS_STORE"
# Add the namespace to wrangler.toml
# kv_namespaces = [
# { binding = "SECRETS_STORE", id = "your-namespace-id" }
# ]
2. Configuring CORS for Multiple Domains
Since we operate on two domains (vanishingvault.com and secretdropbox.com), we needed to configure CORS properly:
// CORS headers function
function corsHeaders(request) {
// Get the origin from the request
const origin = request.headers.get('Origin');
const allowedOrigins = [
'https://secretdropbox.com',
'https://vanishingvault.com',
'http://localhost:3000' // For development
];
// Check if the origin is allowed
const allowedOrigin = allowedOrigins.includes(origin)
? origin
: allowedOrigins[0];
return {
'Access-Control-Allow-Origin': allowedOrigin,
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': '86400',
};
}
3. Deploying the Worker
# Deploy the worker
wrangler deploy
# Configure custom domain routes
# In your Cloudflare dashboard:
# - Add a route pattern: secretdropbox.com/api/*
# - Add a route pattern: vanishingvault.com/api/*
Real-World Use Cases
Our zero-knowledge secret sharing tool is designed to address a variety of secure sharing needs:
- Share sensitive personal information with family members
- Securely transmit passwords to friends
- Send private account details to trusted contacts
- Share temporary access codes without leaving a trace
Conclusion
VanishingVault gives privacy-conscious individuals a secure way to share sensitive information. By leveraging Cloudflare's powerful infrastructure and implementing zero-knowledge encryption, we've created a solution that prioritizes your privacy while remaining simple to use.