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.

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.

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.

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.

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.

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 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.

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.

Found something? Report it privately first, and test with your own account and fake data — not someone else's work.

Contact me →