Security model
What is protected, what is not, which crypto.
This page is blunt on purpose. A tool that overstates its guarantees is worse than none.
What is protected
| Adversary | Outcome |
|---|---|
| The host is breached: stolen tokens, provider CVEs, a rogue employee | They get ciphertext, the members' public keys, sizes and timestamps. They cannot forge a generation (no signing key). They can delete or roll back the vault; that is detected by the hash chain, not prevented. |
| The host is curious | It learns that a vault exists and how often it changes. Not branch names, commit ids, messages, file names, authors, code, comments or logs. |
| A stolen vault push credential | Same as a breached host: garbage is rejected (bad signature), deletion is detected. A protected branch on the host stops rewrites too. |
| A removed member | Loses access to every later generation. What they signed while in stays valid; anything they sign afterwards is refused. What they already fetched stays theirs. |
| A tampered blob, a dropped generation, a replaced manifest | verify, restore and every fetch fail loudly. secretree never appends to a chain it could not verify. |
| The host (or a stolen credential) rolls the vault back to an older state | Every device remembers the newest generation it wrote or saw. A chain that no longer contains it stops every command with an explanation; secretree repair rebuilds the chain from any device's local copy, with a restore proof. |
| A member deletes review comments or other collaboration events and pushes | Never sticks. Event files are unique and append-only; the next sync on any device that had seen them restores them from its own objects, pushes the union back, and reports the deleting commit and its author. |
What happens to deleted data
The collaboration history (pull requests, comments, reviews, checks) is a set of signed files with unique names that are only ever added. Every client keeps a copy of everything it has synced. When a client syncs and finds that files it knows are missing upstream, it does not fast-forward: it restores them, pushes the union, and prints WARNING: <file> was removed upstream by <name> (<commit>); restored. Modifying an event is caught earlier, by its signature.
The vault chain is append-only in the same spirit. A client that recorded generation 42 and finds the host ending at 40, or holding a different generation 42, refuses to continue (vault rolled back) rather than build on rewritten history. secretree repair on any device that holds the data accepts the verified remainder, writes a new full generation from its mirror or work tree (every ref, the collaboration history included) and proves it restorable; everyone else's next sync adopts the repaired chain. What no client ever saw cannot be restored; what one client saw, can.
What is not protected
- A compromised machine that holds a key. Your laptop, your runner. They can read the source directly and the key store as you. This is the trust root by design; nothing running on that machine could change it.
- Traffic analysis. The sizes of incremental generations reveal how busy you are.
- Availability. A host can refuse to serve. Keep two remotes; the format allows any number.
- Losing every key and the printed recovery kit. Nobody can help you then, including the author.
- Secrets inside the repository. They are just more plaintext to secretree; keep them out of git and out of the state archive.
- Deniability or anonymity. The host knows the vault exists and who pushes to it (by its own credentials).
Cryptography
secretree contains no cryptographic primitives of its own.
- Encryption: age, X25519 key agreement and ChaCha20-Poly1305, through the reference Go implementation
filippo.io/age. Every ciphertext is encrypted to all current recipients. - Signatures: OpenSSH signatures (
ssh-keygen -Y sign), Ed25519, namespacesecretree-v1, throughgithub.com/hiddeco/sshsigandgolang.org/x/crypto/ssh. Signatures cover ciphertext, so the chain can be verified without a decryption key. - Integrity: SHA-256 of every ciphertext and plaintext in the signed manifest; SHA-256 of the previous manifest in each one (hash chain).
- Keys are generated on the device and stored in the OS key store; on macOS they are written through
security -iso they never appear in a process listing. A printed recovery kit is the offline copy.
Format
The on-remote format is versioned and frozen: docs/vault-format.md. A vault remains restorable with git, age, ssh-keygen and shasum alone, following docs/restore-by-hand.md; the same instructions sit in every vault's plaintext README.md.
Reporting a vulnerability
Please report privately through a GitHub security advisory on the repository rather than a public issue. The security policy has the details of what is in scope.