How it works

Security you can verify yourself.

We don't ask you to trust our word. Here is exactly how each protection works — and how to confirm it without relying on us.

697,000

subscriber records exposed in the Substack breach, Feb 2026

0 bytes

of your encrypted drafts that Forme can decrypt — ever

7 layers

of independent security — each verifiable without trusting us

01

Your drafts are locked before they leave your browser.

When you encrypt a draft, it's scrambled in your browser before anything is sent. The result that reaches our server looks like random noise. We don't have the key that would unscramble it. We couldn't open your draft even if someone asked us to — not because of a policy, but because of how the math works.

browser-crypto.js

Encryption key generated via Web Crypto API, stored in browser IndexedDB. Content encrypted with XSalsa20-Poly1305 (libsodium). Wire format: base64(nonce[24] || ciphertext). Server stores only the opaque blob — never key, never plaintext.

Verify it yourself

DevTools → Application → IndexedDB → forme-crypto → keys. Your key is there. Save an encrypted draft, then check the Network tab — you'll see a blob, not your text.

02

A subpoena gets us an unreadable blob.

We comply fully with legal process. We hand over everything we have. What we have on an encrypted draft is a scrambled blob and nothing else — no key, no plaintext, no way to decrypt. A court order pointed at Forme cannot produce your unpublished work.

server-store.ts

Server stores only ciphertext. Decryption key never leaves client IndexedDB. Forme possesses: ciphertext, account email, subscription status. Forme cannot possess: plaintext drafts, decryption keys, payment data.

03

Sources reach you from any browser — no downloads, no accounts.

Anyone can submit a tip through your publication's secure intake page. The message is scrambled in their browser before it leaves their device. We receive a sealed package we can't open. You're the only person who can read it — with a key that's stored in your browser and nowhere else.

source-intake.ts

X25519 key agreement + XSalsa20-Poly1305 via libsodium crypto_box_seal. Source encrypts to publication's public key. Only the publisher's private key (IndexedDB) can unseal. Zero knowledge of message content on our servers.

04

Your subscriber list is yours, not ours.

Your readers' payment relationships run directly through your own Stripe account. We store three things per subscriber: their email, their subscription status, and when they joined. No payment data, no location, no reading history, no behavioral tracking. A breach of Forme exposes limited data — and nothing financial.

stripe-connect.ts

Direct Stripe Connect — publisher owns the Stripe account. Forme stores: email, status (free/paid), created_at. Forme never stores: payment methods, card data, location, device fingerprint, IP history, reading behavior.

Verify it yourself

Check your Stripe dashboard — your readers' payment records appear there, not in Forme. Forme's cut on every transaction: $0.00.

05

Photos arrive with the identifying information removed.

Smartphone photos contain more than pixels. They contain GPS coordinates, the exact device model, a serial number, and a timestamp accurate to the second. A person can be identified and located from a single photo. Forme strips all of this in your browser before upload — the identifying data never reaches our server.

exif-strip.js

HTML Canvas redraws pixel data only, discarding all EXIF metadata client-side before upload. Zero EXIF leaves the browser. Verified via ExifTool on any downloaded image.

Verify it yourself

Download an image you uploaded via Forme. Run: exiftool filename.jpg — you'll see no GPS, device model, or timestamp metadata.

06

The warrant canary — proof we haven't been silenced.

We publish a signed statement confirming we haven't received any government orders requiring us to modify our systems or keep silent. The signature uses a cryptographic standard that anyone can verify independently. If we receive such an order and are gagged, we stop signing. The absence of a valid signature is the signal.

canary.ts

Ed25519 signature (libsodium crypto_sign_detached). Signed message: statement + newline + ISO 8601 timestamp. Public key published on publication settings page. Verifiable with any Ed25519 implementation — no trust in our website required.

Verify it yourself

Any Ed25519 library verifies the signature against our published public key. The math either works or it doesn't.

07

If you go dark, trusted contacts can act.

Your encryption key is split into multiple pieces using a mathematical technique called secret sharing. You distribute those pieces to trusted people — colleagues, lawyers, family. If you miss your check-in schedule, those people receive their pieces and can combine them to access or publish your materials. No single person holds complete control.

shamir.ts

Shamir's Secret Sharing (1979). K-of-N threshold scheme — the same mathematics used to secure nuclear launch codes and cryptocurrency custody. Any K shares reconstruct the key; fewer than K reveals nothing, not even a fragment.

Architecture summary

What forme actually stores.

✓ We store (minimal)
Account email address
Subscription status (free/paid)
Published post content
Subscriber join date
Encrypted draft blobs (unreadable to us)
✗ We never store
Payment card data
Decryption keys (ever, anywhere)
Location or IP history
Reading behavior or tracking
Photo metadata (stripped before upload)
Source communication contents

We don't ask for your trust. We offer verification.

Every claim on this page can be checked with freely available tools — open source libraries, browser developer tools, your own Stripe dashboard. The math is public. The code is inspectable. That's the only honest kind of security.

Start your free trial →Why we built this