Security
What the lock guarantees
Confidentiality before the unlock time is cryptographic. Each secret is timelock-encrypted (drand/tlock) to a future round; the threshold-BLS signature that decrypts it does not exist until that wall-clock time. So before then:
- You can't read it early — there's no key to find, no bypass flow.
- GitHub can't read it — the repo holds only ciphertext.
- Anyone who copies the repo can't read it — same reason.
This is a real improvement over a "key sitting next to the ciphertext" design, where anyone with repo access could decrypt at any time.
Trust assumptions
- drand threshold integrity. Decryption depends on the drand "quicknet" network (a ~t-of-n threshold across independent operators, the League of Entropy). The lock holds as long as that threshold isn't compromised before the unlock time.
- drand liveness. The round signature must eventually be published. drand is a robust, multi-organisation network built for exactly this; the chain hash is pinned per secret so decryption is reproducible. If quicknet ever permanently disappeared, affected secrets would become undecryptable. (A future option is to double-wrap with a key you control as outage insurance.)
After unlock
Once a secret's round passes, its signature is public, so anyone with read access to the vault repo can decrypt it. Therefore:
- Keep the vault repo private. (time-safe should refuse to initialize a public repo.)
- "Reveal" decrypts locally and never writes plaintext to disk.
The unlock time is immutable
A genuine time-lock can't be shortened or extended while locked — the ciphertext is cryptographically bound to its round, and you'd need the plaintext (which you can't read yet) to re-encrypt. Renew therefore only works on a secret that's already ready: it reveals and re-encrypts to a new round.
Credentials
- GitHub PAT — stored in your OS keychain (
keyring), never in a plaintext file. Use a fine-grained token scoped to the vault repo; rotate if exposed. - Gmail OAuth (only if you use email delivery) — the refresh token and client secret are stored only as GitHub Actions secrets in the vault repo (written via a libsodium sealed box), never locally. A revoked token surfaces as a GitHub issue prompting you to re-link.
Email delivery carries plaintext
The optional "Email it" path sends the decrypted secret to the delivery address via Gmail at/after the unlock time. If you'd rather plaintext never traverse email, use local Reveal instead (the default), which keeps it on your machine.
Out of scope
- Malware on your machine (a keylogger/memory scraper could capture plaintext at reveal time).
- Compromise of the delivery email account (if you use email delivery).
- A determined attacker who already has read access to a vault repo after its secrets unlock.
For protecting secrets from a third party (rather than from your future self / premature access), use a purpose-built secrets manager.