Agni Blog

Random thoughts from the people building this thing. Usually about encryption, sometimes about coffee.

We Built This So We Could Sleep at Night

The real reason we went zero-knowledge isn't some grand vision. It's that we kept asking: what happens when someone gets root?

About two years ago, before Agni was called Agni, I was at a security conference in Berlin. Someone gave a talk about a major email provider that got fully compromised — not the users, the *infrastructure*. The attackers didn't need passwords. They just... read everything. Because the keys were right there on the same machines as the data.

I remember walking out of that talk and calling the other two people who eventually became co-founders. "What if we just... didn't have the keys?" It sounded almost stupidly simple. Like, could you even build an email service where the server is literally incapable of reading the mail?

Turns out, yes. But it makes everything harder. You can't do server-side search. You can't recover forgotten passwords — we can only nuke the old key and start over. You can't train a spam filter on message content because you don't see the content. We had to build an entire SMTP edge that encrypts incoming mail *before* it touches disk, using the recipient's public key that we don't have the private half of.

Is it overkill for most people? Probably. But the thing is, once you've architected it this way, you can't accidentally screw it up later. We literally *cannot* comply with a request for plaintext. Not because we don't want to — because mathematically, we don't have it. That's the only kind of privacy guarantee I personally trust.

"End-to-End Encryption" Is a Meaningless Marketing Term Now

Every service claims it. Almost none of them mean what you think they mean. Here's the cheat sheet I wish someone gave me.

I keep seeing ads for "encrypted email" services where the encryption happens... on the server. Like, great, the hard drive is encrypted. But the server still holds the keys. The service provider can still read everything. A court order still works. An employee with database access still sees your emails. That's not privacy — that's compliance theater.

Then there's the escrow crowd. "Your keys are encrypted on your device, but we keep a backup just in case!" Just in case of what? In case you forget your password? Here's a wild idea: write it down. The whole point of encryption is that *only you* can unlock it. If there's a backup key somewhere, it's not only you. Full stop.

Real zero-knowledge means: keys generated in your browser. Private key encrypted with your password. Ciphertext stored on our servers. We don't have your password. We don't have your key. We store the encrypted blob and that's it. If you lose your password, you lose your data. That's the deal. If a service promises recovery AND true privacy, they're lying about at least one of those things.

I'm not saying convenience doesn't matter. It does. But you should know what you're trading. We chose the paranoid route because once you realize how many "encrypted" services can actually read your stuff, it's hard to unsee it.

One Login. Finally.

We used to have three separate auth systems. It was a mess. Here's how we fixed it — and why we had to get a little creative with cross-domain sessions.

When we launched AgniVault, it had its own auth. When we added AgniVPN, it got its own too. So you had three passwords, three login screens, and a lot of confused users asking why their mail password didn't work for file sharing.

We moved everything to a single JWT session. Same secret, same format, same localStorage key across all products. The catch? agni.sh, mail.agni.sh, priv.agni.sh, and files.agni.sh are different domains — browsers don't share localStorage across origins. So if you log in on the landing page and click through to mail, you'd land on a site that has no idea who you are.

Our solution is kind of hacky but it works: when you leave one Agni domain for another, we pass your session token in the URL hash. The receiving site grabs it, stores it in its own localStorage, and wipes the hash before you notice. It's not magic — it's just a handoff. The JWT itself is signed with HS256 and rotates per deployment, so even if someone intercepted that hash, they'd need the secret to do anything with it.

It's not as seamless as a shared cookie, but it means you log in once and you're in everywhere. And more importantly: we don't need a central auth server that becomes a single point of failure. Each product validates the JWT independently.

OpenPGP Is Ancient and I Love It

Everyone wants to invent their own shiny crypto protocol. We went with the boring old standard instead. Here's why that wasn't actually a boring decision.

I get why Signal built the Double Ratchet. I get why Matrix has Olm. They're elegant, they're modern, they solve real problems. But here's what nobody talks about: if Signal shuts down tomorrow, your Signal messages are gone. The protocol is tightly coupled to the app. You can't export your keys and open them in something else.

OpenPGP is the opposite of elegant. It's verbose, it's old, the user experience is... well, you've tried using GPG on the command line. But it's a documented standard with RFCs and independent implementations. Your AgniMail keys are just OpenPGP keys. Export them, import them into Thunderbird, use them with GpgSuite, whatever. If we disappear, your encrypted mail is still readable with any OpenPGP tool.

We use Sequoia-OpenPGP on the backend — it's Rust, it's audited, it's solid. In the browser we use OpenPGP.js. Same standard, different implementations, and they agree on the wire format. That's the kind of redundancy I actually care about.

Could we have built something prettier? Sure. But email is the most interoperable communication system ever built. It would be insane to lock that interoperability behind a bespoke protocol. We chose the ugly, reliable standard. No regrets.