The moment I realized my backend could still read everything

formseal didn't start as a cryptography project. It started as a contact form - the most boring thing you can build. I had a small personal site and I wanted a way for people to reach me without my email address being scraped. Nothing clever about it.

I used hosted backends for a while. They worked fine, but at some point I got uncomfortable in a way I couldn't fully articulate at the time. Every message I received existed as plaintext somewhere I didn't control. The trust model was basically: hope the provider is ethical, hope their dashboards aren't breached, hope nobody with access decides to go snooping. HTTPS handled the message while it was moving, but the moment it landed, some stranger's database had the full thing.

That bothered me enough that I decided to build my own backend. Cloudflare Workers and KV, no frameworks, no dependencies worth mentioning. I wanted to understand exactly what was happening to data as it moved through the system. It felt cleaner. More honest.

And then I realized, obviously, that Cloudflare could still read everything. I had just moved the problem one layer to the left. I'd reduced dependency ownership without reducing trust ownership, which is a much harder thing to actually change.


The question that changed everything

Once I framed it that way, the right question became pretty obvious: why does the backend need to see plaintext at all?

There's no good answer. The backend doesn't need to understand a message to store it. It doesn't need to read it to return it later. The only reason it sees plaintext is because nobody bothered to encrypt before sending.

So I moved encryption into the browser. Before a message ever leaves the page, it gets encrypted with a public key that only I have. The architecture went from:

formseal before

to:

formseal after

The backend went from being a reader to being a bucket. Receive ciphertext, store ciphertext, return ciphertext. That's where formseal actually became formseal.


Early overengineering

The early versions were way more complicated than what exists now. I experimented with spam protection schemes, challenge-response flows, browser-side admin workflows, inbox-like ideas for managing submissions. Some of it was genuinely interesting to build. Most of it was solving problems adjacent to the real problem, and adding surface area in the process.

I eventually noticed a pattern: every time I removed a feature or a responsibility from the system, things got better. The version that does less is consistently more trustworthy than the version that does more, because there's less to go wrong and less to audit.

This sounds obvious in retrospect but it took a while to internalize. In security tooling especially, the question worth asking about every feature isn't "does this add value?" - it's "does this add more trust surface than it's worth?"


The naming mistake I made

The decryption tool was originally called formseal-inbox. I imagined it becoming a terminal inbox - messages, viewing, maybe a full TUI someday. That never happened because it was never the right idea. The tool's actual job was always just: take ciphertexts, produce readable output. Nothing more.

But because it was called "inbox," I kept entertaining features that would have pushed it toward becoming a database browser or a mini dashboard. The name was creating scope creep by implication. Renaming it to formseal-decrypt killed a lot of bad ideas immediately.

Naming is architecture. A bad name quietly creates bad scope.


On "security aesthetics"

Looking back at my notes from a couple years ago, there's a lot of stuff that was aesthetically security-focused without being actually rigorous. OPSEC-y language. "Digital minimalism." Anti-surveillance vibes as a personality rather than a threat model. Some of that intuition was useful - the distrust of opaque third parties, the preference for self-hosting - but a lot of it was just aesthetics.

What actually changed my thinking was learning to be specific about what I was protecting against: what is the actual attack surface? What guarantees can this system make, and what would it take to violate them?

[!NOTE] formseal is honest about its limits. Browser-side encryption doesn't help you if your device is compromised or your private key is stolen. It narrows the trust surface during normal operation. That's the guarantee, stated plainly, not dressed up as something bigger.


What it doesn't do

formseal doesn't manage hosting. Doesn't have a dashboard. No accounts, no inbox, no analytics, no workflow tools. Its scope is narrow on purpose, because the moment you start owning the workflow, you also start owning the trust. And the whole point was to stop doing that.

None of this started from crypto. It started from a nagging discomfort: "encrypted in transit" is not the same thing as "the backend can't read it." Following that distinction to its logical conclusion is basically the entire project.