Built to be unreadable.
By design.
Zero-knowledge isn't a policy — it's a technical constraint. Here's exactly how Wispr makes it impossible for us to read your data.
AES-256-GCM
Encryption algorithm
PBKDF2 / AES-KW
Password key wrapping
100,000
PBKDF2 iterations (SHA-256)
Encryption
Everything encrypted in your browser — nothing readable ever leaves your device.
Client-Side AES-256-GCM
Your browser generates a random 256-bit AES key and encrypts your message or file using GCM mode before any network request is made.
- Key generated with Web Crypto API (CSPRNG)
- GCM mode provides authenticated encryption — tampering is detectable
- 12-byte random IV generated per secret
- Server receives only: ciphertext + IV (both useless without the key)
Key Never Sent to Server
The encryption key lives only in the URL fragment (#key=...). Browsers never include the fragment in HTTP requests — it's a web standard constraint, not a policy.
- URL fragment (#hash) is client-only — not in request headers, logs, or referers
- If you share the link via email, the key is still never exposed to servers
- Even if our server is fully compromised, keys cannot be extracted from logs
Password Key Wrapping (PBKDF2 + AES-KW)
Password-protected secrets use PBKDF2 to derive a wrapping key from your password locally, then wrap the AES key with AES-KW. The password never leaves your browser.
- PBKDF2-SHA256 with 100,000 iterations — computationally expensive to brute-force
- Random 16-byte salt generated per secret
- Wrapped key stored on server — useless without the original password
- For password-protected secrets, the URL contains no key fragment
Authenticated Encryption
AES-GCM includes a built-in authentication tag. Any tampering with the ciphertext — by us, an attacker, or a network middleman — will cause decryption to fail.
- 128-bit authentication tag per encrypted block
- Decryption fails immediately if ciphertext is modified in transit
- Prevents chosen-ciphertext attacks
- No silent failures — corruption is always detected
Anonymity & Privacy
What we collect, what we don't, and how we minimize your exposure.
No Tracking, No Analytics
Wispr contains zero third-party scripts. No Google Analytics, no Mixpanel, no Sentry, no ad networks. Your visits generate no fingerprinting surface.
- No JavaScript from external domains loads in the browser
- No localStorage/sessionStorage for tracking — only UI state
- No cookies of any kind
- Content Security Policy blocks any unauthorized external scripts
Minimal Server Logs
Server logs record only: HTTP method, URL path (no query strings), status code, and response time. IP addresses appear in system-level logs and are purged within 30 days.
- Query strings stripped from all log entries
- No message content, keys, or passwords ever appear in logs
- URL fragments are never sent to the server — not loggable by definition
- Log purge cycle: ≤30 days
Tor & VPN Friendly
Wispr works over Tor Browser and VPNs without degradation. We don't block Tor exit nodes or flag unusual IP ranges. Anonymity tools should work with anonymity tools.
- No Tor exit node blocking
- No CAPTCHA challenges triggered by unusual IPs
- No behavioral fingerprinting or IP-reputation gating
- JavaScript-minimal design works with strict Tor Browser settings
No Account Required
Creating or receiving a secret requires zero personal information — no email, no phone, no name. The only identifier is the random secret ID.
- Secret IDs are 16-character nanoid strings (~80 bits of entropy)
- No user accounts, sessions, or authentication tokens
- No correlation between secrets you create
- Custom slugs are optional — auto-generated IDs are fully random
Infrastructure Security
Server-side hardening and transport security.
Security Headers
Every API response includes a strict set of security headers to prevent common web attacks.
- Content-Security-Policy — blocks unauthorized script execution
- Strict-Transport-Security (HSTS, 1 year, preload) — forces HTTPS
- X-Content-Type-Options: nosniff — prevents MIME sniffing
- Referrer-Policy: no-referrer — prevents URL leakage in referers
- Permissions-Policy — disables camera, mic, geolocation, payment
- X-Frame-Options (via CSP frame-ancestors: none) — prevents clickjacking
Rate Limiting
API endpoints are rate-limited to prevent brute-force attacks and abuse.
- Global: 200 requests per 15 minutes per IP
- Secret creation: 30 secrets per hour per IP
- Reveal endpoint: 60 attempts per 15 minutes per IP
- Standard rate-limit headers returned on all responses
Burn-After-Reading — Server Enforced
Burn-after-reading is enforced at the database level. On reveal, the row is hard-deleted from PostgreSQL immediately — not flagged, not soft-deleted.
- Hard DELETE on reveal — permanent and unrecoverable
- Even if someone captures the link, revealing once burns it for everyone
- Expired secrets deleted on next access attempt
- Max-view limits enforced atomically with deletion
Zero Server-Side Key Material
The server's database contains only ciphertext, IVs, and (for password secrets) wrapped key material. The actual encryption key is architecturally absent.
- No plaintext content ever written to the database
- No raw AES keys ever transmitted to or stored by the server
- Wrapped keys are useless without the user's password
- A full database dump would contain only encrypted blobs
Input Validation & Type Safety
All API inputs are validated with Zod schemas generated from the OpenAPI specification. Malformed requests are rejected at the boundary.
- Zod schema validation on every request body
- Type-safe Express routes — no untyped req.body access
- 50MB JSON body limit enforced at the application layer
- Custom slugs validated against strict alphanumeric regex
Database Encryption at Rest
PostgreSQL data is encrypted at rest on the server infrastructure. Even physical access to storage would not expose readable data.
- Database encrypted at rest by hosting provider
- Combined with application-level AES-256-GCM encryption per secret
- Two layers: transport TLS + storage encryption
- No database credentials in application code — environment variable only
Threat Model
What Wispr protects against — and what it doesn't claim to.
Wispr server compromise / database breach
Server stores only encrypted blobs. Without the key, a full database dump is useless.
Network interception (MITM)
TLS encrypts transport. The key is in the URL fragment, which is never transmitted.
Server-side logging of content
No plaintext content, keys, or passwords are ever present on the server to log.
Recipient's device being compromised
Once decrypted in the recipient's browser, Wispr has no control over what happens to it.
Screenshots or copy-paste by the recipient
Burn-after-reading prevents re-access, but cannot prevent the recipient from saving the plaintext.
Weak or reused passwords
PBKDF2 with 100k iterations slows brute-force, but a guessable password is still guessable.
Legal compulsion to produce data
We can only produce what we store: encrypted blobs and metadata. No keys, no plaintext. We cannot decrypt on behalf of any party.
Link URL shared over an insecure channel
If the link (including the #key fragment) is intercepted before the intended recipient clicks it, the secret can be read. Treat the link itself as the secret.
Legal & Government Requests
What happens when law enforcement asks for your data.
What We Can Produce Under Compulsion
If compelled by law, we can hand over only what we store — which is deliberately minimal and useless without keys we don't have.
- Encrypted ciphertext (AES-256-GCM — unusable without key)
- IV and wrapped key material (for password-protected secrets)
- Metadata: creation time, expiry, burn setting, view count
- No content, no keys, no passwords — not by policy, by architecture
Warrant Canary
We publish a warrant canary that is updated regularly. If it goes dark, it may indicate we have received a secret government order we cannot disclose.
- Canary updated at regular intervals
- Absence of update signals possible legal constraint
- See the /canary page for the current status
- Read about warrant canaries in our blog
Minimal Metadata Retention
The only metadata we retain is what's functionally necessary to serve the secret. We do not log who created a secret or who revealed it.
- Creation timestamp (needed for expiry logic)
- View count (needed for max-views enforcement)
- No sender identity, no recipient identity
- No IP-to-secret correlation in application-level logs
Proton Mail Contact
Our contact email is hosted on Proton Mail — end-to-end encrypted by default when writing from a Proton address. We picked it deliberately.
- [email protected] — Proton-to-Proton messages are E2E encrypted
- Security disclosures should use this address
- Or use a Wispr link itself for maximum privacy
Technical Specifications
Authenticated encryption with 128-bit tag
100,000 iterations, random 16-byte salt
RFC 3394 — wraps the AES key for password secrets
Randomly generated per secret via CSPRNG
Generated via Web Crypto API
16-character nanoid, URL-safe alphabet
Browser-native, no third-party crypto libraries
HSTS enforced, 1-year max-age with preload
Encrypted at rest on server infrastructure
System-level logs only; no content
Maximum encrypted payload per request
Open-source, auditable
Found a vulnerability?
We take security reports seriously. If you've found a vulnerability, please disclose responsibly — we aim to respond within 24 hours. We won't pursue legal action against good-faith researchers.
Use Wispr itself to send an encrypted report