Threat model¶
This is the threat model for the CLI, not a third-party audit.
Assets¶
Plaintext secrets on disk after
unsealorgetPer-file data keys in
.vault/keys.*The signed manifest (the trust root: paths plus blob digests)
Ciphertext blobs in git history (they outlive
rotate --rekey)
Adversaries¶
Anyone who can clone the remote (ciphertext and the encrypted name map)
A machine that is later lost (its private key still opens the wrap group it was given)
A local uid that can read world-readable temp files
A malicious pull request running in CI
What the commands buy¶
Command |
Gives |
Does not give |
|
blob digests still match the signed manifest; no key needed |
that you can decrypt; that git history is gone |
|
a removed recipient can no longer unwrap the data keys |
post-compromise secrecy for a leaked data key |
|
new data keys and new payloads |
erasure of old objects on the remote |
|
local plaintext vs the recorded content hash |
blob integrity |
|
unvaulted secret-shaped literals on disk |
a complete detector |
Trust root¶
The manifest is signed. Age payloads have no in-band signature; GPG v5
blobs do. v6 payloads are symmetric and unsigned in-band. Authenticity
for those is the signed manifest plus the blob digest unseal and get
check before decrypting.
Key files are encrypted and not signed. A tampered key file fails to decrypt rather than forging plaintext.
Limits that stay¶
Filenames are hidden; counts, sizes and mtimes of blobs are not.
There is no forward secrecy: old ciphertext in git history still opens with an old data key.
A private vault repository is the way to keep ciphertext off a public remote. Rotation cannot reach the GitHub fork network.
--allow-unsignedis a migration hatch. It is not a daily mode.
In-repo review (2026-09)¶
Not a third-party audit. Findings from reading src/ and the test suite,
then fixing what was independently true:
add/rm/mv/add-dirused to drop the seal-key header (fixed).addused to write v5 blobs into a v6 vault (fixed).Plaintext and data keys used to land in
.vault/.plainand pid-named/tmpfiles (fixed).add-dirused to follow symlinks out of the named tree (fixed).geton a GPG v5 blob used tostripthe secret (fixed).checkused to pass a v6 vault with no key file (fixed).One combined
manifest.gpgis last-writer-wins on two adds; per-entry records under.vault/e/close that (nimvault-k0fo).
Accepted:
Absolute paths outside
$HOMEwith norootare the caller’s choice.Unsigned GPG in-band signatures on key files stay unsigned so a second machine does not need the signer’s public key to decrypt.
Third-party review is not commissioned from this sitting.