Why Do Slack and Email Fail at Sharing Secrets?

Because they leave permanent traces — a credential pasted in chat history sits there forever, waiting to be found by someone who shouldn't have it.

Developers share sensitive information constantly — API keys, database credentials, environment configs, SSH keys. The usual approach? Paste it in Slack, email it, or drop it in a shared doc. All of these leave permanent traces. The credentials sit in chat history forever, waiting to be found by someone who shouldn't have them.

We needed something better: a way to share secrets that disappear after being read, where even we can't see the content. That's why we built Psst.

How Do You Build a Server That Never Sees the Plaintext?

By encrypting entirely in the browser with the Web Crypto API and keeping the decryption key out of every request the server ever receives — the server only ever stores an opaque blob.

The core design principle is simple: the server never sees plaintext. All encryption and decryption happens in the browser using the Web Crypto API.

When you create a document, Psst generates a random AES-256-GCM key in your browser. The content is encrypted before it ever leaves your machine. The server receives only the ciphertext — an opaque blob of bytes that means nothing without the key.

The encryption key lives in the URL fragment (the part after #). URL fragments are never sent to the server — this is part of the HTTP specification. So when you share a Psst link, the recipient's browser extracts the key from the fragment, fetches the ciphertext from the server, and decrypts locally. The server is just a dumb storage layer.

What Does Adding a Password Actually Protect Against?

Link interception — with password protection on, the key is derived from the password via PBKDF2 instead of embedded in the link, so having the URL alone isn't enough to decrypt.

For extra security, you can add a password. When password protection is enabled, the encryption key is derived from the password using PBKDF2 (Password-Based Key Derivation Function 2) instead of being randomly generated. The password itself is hashed with SHA-256 before being sent to the server for verification.

This means even if someone intercepts the share link, they still can't decrypt the content without knowing the password. Two layers of protection: something you have (the link) and something you know (the password).

How Do Documents Actually Self-Destruct?

Three ways — time-based expiry, view-count expiry, or burn-after-reading — all handled by Redis TTL and access counters, with no cron job doing the cleanup.

Psst supports three types of automatic destruction:

  • Time-based expiry — documents auto-delete after 5 minutes, 1 hour, 1 day, 7 days, or 30 days
  • View-based expiry — documents delete after 1, 3, 5, or 10 views
  • Burn after reading — one-time links that self-destruct after the first view

Under the hood, Redis handles this elegantly. Time-based expiry uses Redis TTL (time-to-live) on keys — Redis automatically deletes expired keys without any cron jobs or cleanup tasks. View-based expiry increments a counter on each access and triggers deletion when the limit is reached.

Why CodeMirror 6 Instead of a Plain Textarea?

Because Psst needed real syntax highlighting across 11 languages, 7 themes, and Markdown/HTML/JSON live preview — a plain textarea can't do any of that.

Psst isn't just a paste bin — it's a proper code editor. We chose CodeMirror 6 for its modern architecture, extensibility, and performance. It supports syntax highlighting for 11 languages (JavaScript, TypeScript, Python, HTML, CSS, JSON, Markdown, YAML, SQL, Shell, XML) with automatic language detection based on content.

The editor includes 7 themes: Xcode (our original), Dracula, Monokai, Nord, Solarized, GitHub, and Olive. Dark and light modes are supported with persistent preference. We added zoom controls (10-24px font size), line highlighting with URL hash linking (#L42), and live preview for Markdown, HTML, and JSON.

Why Does a 220-Line Backend Work Here?

Because a zero-knowledge server only ever stores and retrieves encrypted blobs — there's no business logic to justify a heavier framework than Express.

React 19 + Vite 7 for the frontend. Fast builds, modern JSX, and excellent developer experience. Express.js for the API — the entire backend is 220 lines of code. When your server is just storing and retrieving encrypted blobs, you don't need a complex framework.

Redis was a natural choice for document storage. Documents are ephemeral by design — they're meant to be deleted. Redis natively supports key expiry, which maps perfectly to our self-destruct feature. No migrations, no schema, no ORM. Just key-value pairs with TTLs.

How Do You Deploy Without Opening Any Ports?

With Cloudflare Tunnel — an outbound-only encrypted connection to Cloudflare's edge means the server's real IP is never exposed to port scanning at all.

Psst runs on a self-hosted machine via Docker Compose. Instead of opening ports on the router or setting up a traditional reverse proxy chain, we use Cloudflare Tunnel. The tunnel creates an encrypted outbound connection from our machine to Cloudflare's edge network. Traffic flows through Cloudflare without any inbound ports being open.

This means the server's real IP is hidden, there's no attack surface from port scanning, and DDoS protection comes free from Cloudflare's edge. DNS is a simple CNAME to the tunnel endpoint — no A records pointing to our infrastructure.

What Did Building Psst Teach Us?

URL fragments are an underused encryption-key channel, Redis TTL replaces a whole class of cleanup jobs, Cloudflare Tunnel removes infrastructure exposure entirely, and small backends are easier to trust.

  • URL fragments are powerful — the # portion of a URL is never sent to the server, making it perfect for encryption keys
  • Redis TTL is underrated — automatic key expiry eliminates an entire class of cleanup jobs
  • Cloudflare Tunnel simplifies everything — no port forwarding, no dynamic DNS, no exposed infrastructure
  • Simple backends win — 220 lines of Express handles all of Psst's server-side logic

Try It

Psst is free to use at psst.blockb.ca. No account required. Share code, credentials, or confidential notes with links that self-destruct. Check out the product page for a full feature overview.