The "Crash-safe rotation WAL" feature sounds sketchy and it's what I'd audit closely, if I was auditing closely.
The crash-safe WAL is the part I'm most nervous about too. That's exactly why I posted this. I want eyes on the rotation logic specifically.
And yeah, single bbolt db is a limitation. I could have used pebble or any other, but trade-off for simplicity (a single *.db). A true WAL will need external file. The storage is pluggable though also open to improvement.
Still very young.
I didn’t get a chance to do a write up but the golang port is here: https://github.com/neosmart/securestore-go
The approach to crypto is very different, we went with what’s very well understood and very well supported on all platforms with little or no dependencies (eg we can use web crypto in JS frontend or backend with no external libs or crypto JS library nonsense).
The original .NET and Rust code is from over a decade ago and carefully architected (well before vibecoding was a thing), the secrets are stored in a human readable (json) vault that can be embedded in your binaries or distributed alongside them and be decrypted with either password-based or key-based decryption (or both).
The rust repo has the most info: https://github.com/neosmart/securestore-rs
The JSON vault + cross-language portability is nice too, especially if you’re embedding secrets across services without tying yourself to one runtime. Curious how you handle key management at scale though — that’s usually where these systems get tricky more than the crypto itself.
The problem fnox solves is great, unified access to secrets across dev, CI, prod with cloud backends. That's a different layer of the stack.
Keeper solves a lower-level problem: you have a Go process (a load balancer, a control plane, a daemon) that needs to store secrets inside its own database not in a separate file, not in a cloud vault, not in env vars. Secrets that need per bucket isolation, audit trails, and crash-safe rotation.
Here is my thinking :
- fnox = how your CLI and deploy scripts get secrets
- Keeper = how your running binary stores secrets at rest
Different problems, Could I build Keeper on top of fnox? Probably. But then I'd have a file on disk with secrets that fnox manages which is exactly the problem I wanted to eliminate.
But they require to be placed on a separate server, and come with their own infra management.
Is the idea of this project to embed this into you app, instead of relying on .env or an external vault?
The primary issue has been not being able to manage an encrypted storage system… the main goal is to have something that can be audited, not just secured.
yes 100% ... embeded
Vault gives time limited Tokens with Network Boundary. Instead of Keeper, i would just use age:
# write
echo "my secret" | age -r <recipient-pubkey> > secret.age
# read
age -d -i key.txt secret.age
This is an age+filesystem secrets manager that I made that is basically what you wrote, but with more organization.
This kind of thing is super common in vibecoded crypto, I wonder why it keeps happening.
Edit: here is an example of the process and output with something I put together the other day: https://github.com/RALaBarge/garlicpress/blob/master/portfol...
I haven't used it, don't advocate for it, and have no opinion on either its viability or your product's viability for any specific use case. Mostly I just think it's a bit confusing to have two separate products in a very similar space with the same name.
Different trade-offs though, Keeper is library first embedded. secret does per version keys with symlink switching - nice, Keeper does per-bucket DEK isolation + audit chains. Both solve "encrypted local storage" but for different workflows.
I'll definitely be looking through your code for ideas