Security at Facets
Facets is a local-first, end-to-end encrypted workspace for small teams that actually trust each other. Your notes, tasks, files, and Spaces live on your device first. Sync moves them between your devices and your collaborators — it doesn't move them through me.
This is the plain version of how that works: what Facets protects, where the protection stops, and what receipts exist for the claims. No magic words.
One thing up front, because it shaped everything below. I build Facets navigating entirely by VoiceOver. I can't eyeball a diff and feel that the trust boundary is still intact. So the security model isn't a story I'm asking you to believe — it's written down as formal models you can read and check yourself. The constraint turned out to be the feature.
Security by design
Your work starts on your device.
The real copy of your work is local. Facets keeps it in an encrypted database (SQLCipher) on your machine, with the keys held by the native runtime and your OS — not by the web interface you click around in. Turning on sync adds an encrypted transport on top of that. It doesn't relocate your work somewhere I can read it.
The relay is a courier, not a vault.
Sync works by passing sealed envelopes between devices. Each envelope is encrypted with a key derived from your group's OpenMLS session before it ever reaches the relay. TLS protects the connection too, but that's the lesser point — the contents are already sealed. The relay's job is to carry envelopes. If it's buggy, curious, or hostile, the design goal is that it still can't read your work or hand one person's authority to someone else.
Sign-in is scoped on purpose.
Facets uses Clerk for one narrow job: authenticating a device when you link it for sync, and activating billing. That's the whole scope. Your identity on your own device is a passkey (WebAuthn) — local, hardware-backed, never a password I store. Clerk never sees your work, so a Clerk problem is a sign-in problem, not a read-your-notes problem. I'd rather name the dependency than let you assume there isn't one.
Removed devices stay removed.
Pulling a device off your account isn't cosmetic. The models check that a stale or removed device can't keep authoring future changes. A compromised device — stolen while live — is handled more strictly than "I retired an old laptop," because those aren't the same emergency.
Restore relinks before it trusts.
Backup and restore are dangerous if they hand authority back too easily. Restoring old encrypted data goes through a relink step before fresh sync authority returns, so an old backup can't quietly resurrect old access.
Files and backups are sealed before they leave.
Files are encrypted before remote object storage sees them. Backups, when you enable them, are encrypted before they're stored. The storage provider holds ciphertext.
What the models actually prove
Encrypted systems fail in a boring, specific way: somewhere in the code, after swearing the server is untrusted, you accidentally trust it. Writing the design down as models is how you catch exactly that.
Parts of Facets' design live in the repo as formal models, checked with tools — ProVerif for the crypto protocol, TLA+ for the state machine, Isabelle/HOL for the data model, Kani for bounded Rust invariants. They answer questions like:
- can the relay read plaintext? (it shouldn't)
- can a sync message from one Space be replayed into another? (it shouldn't)
- can a removed device keep writing? (it shouldn't)
- can restore skip the relink step? (it shouldn't)
- does a trust check actually check trust, rather than invent it?
What they don't claim: that there are no implementation bugs, that the shipped product has been audited, that metadata is hidden, or that a compromised device is still safe. The models are receipts for the design, not a proof that every line is perfect.
You can read them. Repo: github.com/blinding-pixels/Facets — models under Docs/security-verification, alongside the result notes and the adversarial test harness.
What Facets can't protect
No app saves you from everything, and cryptography doesn't fix a compromised endpoint. Facets can't protect against:
- malware or a keylogger already running on your device
- someone watching your screen, or using your unlocked machine
- recovery words or a passphrase handed to the wrong person
- a malicious accessibility process on your system
- anything you export, screenshot, copy, or move out of Facets on purpose
- the fact that metadata exists
- relay downtime, or someone blocking the network
- bugs nobody's found yet
If the device is owned, the math doesn't save you. That's true of every end-to-end encrypted product; I'd rather say it plainly than imply otherwise.
Metadata exists
Encrypted sync is not the same as invisible. To run the service, Facets keeps the operational records it needs: accounts, device-link records, Space membership, billing and quota state, timestamps, encrypted-envelope records, and logs. That isn't your document text or file contents — but it's still information about the service being used, and I'm not going to pretend it isn't there.
No independent audit yet
Facets has public source for the client, public formal models, result notes, conformance notes, and tests. Those are real, and you can check them today.
What Facets does not have: an independent third-party audit of the shipped product, or SOC 2. No outside firm has reviewed the full product and signed off. If that changes, this page will say what was audited, when, which version was in scope, and what wasn't.
The stack
The building blocks, so you can see where trust lives:
Rust, Tauri
the native runtime that owns keys, crypto, storage, and sync
SQLCipher
encrypted local storage
OpenMLS
group key agreement for sync envelopes
AES-GCM, HKDF, HMAC, SHA-2
the encryption and key-derivation primitives used by the Facets crypto layer
Ed25519 Dalek
signatures for authority-bearing records
zeroize
best-effort cleanup for Rust-owned secret buffers
rustls
TLS for network transport
WebAuthn / passkeys
local identity
Yjs, ProseMirror
the document model
Clerk
the one hosted identity dependency, scoped to sync device-link and billing
Backblaze B2, Cloudflare Workers
encrypted file storage and relay infrastructure
ProVerif, TLA+, Isabelle/HOL, Kani
the verification tools
Boring where possible, inspectable where it counts.
FAQ
Can Facets read my synced work?
No — your work is encrypted on your device before it leaves. Also, I'm a jazz musician, not Google; realistically I have no interest in your data. I made this app for myself, and now I'm putting it out for everyone to use.
Is Facets zero-knowledge?
I'm not using that phrase. It means too many different things to too many people, and I don't want a marketing term doing work the architecture should do. The honest claim is the metadata mentioned above is used to sync your data around. Apart from that, the relay only transports encrypted data. The client code is public, so anyone can audit it themselves.
What does "formally modelled" mean?
Parts of the design were written down as models and checked with tools. Until recently I had no idea you could even do this. These tools take a model of your app and verify whether your claims hold — not because you said so, but because they're actually proven. Kinda like proving a theorem: once it checks out, it holds for every case, not just the handful you happened to test.
Has Facets been independently audited?
No. Not yet. But hey — if you wanted to pay for that, I'd be more than happy to talk.
What if my device is compromised?
Then the problem is bigger than Facets. The design can keep plaintext away from the server; it can't make an infected device safe. Your teammates can, however, mark your device as compromised and stop it from syncing.
What if I export a file?
Once it leaves Facets, it's outside Facets' protection. The app can't guard a copy you moved somewhere else.
Reporting a problem
Found something? Report it privately first, and test with your own account and fake data — not someone else's work.
Contact me →