Killing Infisical, Building My Own Secret Store

I ran my secrets through Infisical for a year, then replaced it with a 300-line Node/Express daemon in an Alpine LXC — AES-256-GCM, an MCP interface, and the realization that a secret manager is just a tiny API.

For over a year, every secret in my life lived in Infisical — a self-hosted instance on pve1 that held deploy tokens, API keys, and sudo passwords for a dozen machines. It worked. It was also a heavyweight way to store a few dozen strings, and every time I needed a value mid-session the flow was: open the vault, find the workspace, click copy, hope I pasted the right thing into the right shell.

Then I looked at what I actually needed and built the smallest thing that could hold it. A couple of hundred lines of Node, one SQLite file, one Alpine container. It's been my only secret store for a week now, and honestly the most surprising part is that I didn't do it sooner.

Why I left Infisical

The short version: overkill. My usage was:

  • A few dozen keys, grouped by project and machine.
  • Read access from three or four different AI client configs (Claude, Gemini, OpenCode).
  • The occasional write when I rotated a token or added a new server.
  • Deploy scripts that need to inject a value into an environment without it ever showing up in a transcript.

Infisical has RBAC, audit logs, environments, a web UI, a CLI, a client SDK — the works. I used roughly 10% of it, and the cost wasn't the disk usage, it was the ceremony. Every interaction had a six-step URL, a workspace switcher, a secret-path hierarchy. For a solo operator it was a filing system I had to manage instead of a tool that helped me.

So I tore it down and wrote the alternative. The requirements were brutal and simple:

  • Store key/value pairs, AES-256-GCM encrypted at rest.
  • Serve them over HTTP to authorized clients.
  • Expose an MCP interface so my agents can use it natively.
  • Zero leaks: when an agent runs a command with a secret injected, the secret never appears in the transcript.

What it actually is

The whole thing fits in one Alpine LXC (CT 132) running a small Express app:

  • Storage: SQLite with AES-256-GCM. The master key lives in the OpenRC init script (/etc/init.d/secret-store), never sent to clients.
  • Auth: a bearer token. The MCP client gets the URL and the token; the master key stays on the box. Restore and rotation are one file edit away.
  • API: list keys, get a value, set, delete, rename, update a description.
  • MCP tools: secret_list_keys, secret_set, secret_delete, secret_verify_key, and the important one — secret_exec_command, which runs a shell command with secrets injected via envMapping and redacts them from the output in real time.

That last tool is the whole thesis. The reason I switched wasn't storage, it was leakage. Every AI session that needs a deploy token used to mean pasting the token into a prompt or a log line. Now the workflow is: secret_list_keys to find the key, secret_exec_command to run the deploy with it injected, and the secret never appears in the conversation. The store isn't just a vault anymore — it's a sandbox that keeps secrets out of transcripts by construction.

The deployment path

The source of truth is a Gitea repo. ./deploy.sh syncs the code through pve1 (192.168.88.10), pushes it into LXC 132 (192.168.88.116), and restarts the service. One command, idempotent, and the whole surface area is small enough that I can read the entire server in one sitting — which is exactly the kind of confidence a secret store should inspire.

What I learned

  • A secret manager is just a tiny API. Everything Infisical sold me on — RBAC, environments, audit trails — was solving problems I didn't have. What I actually needed was set and get with good auth. Build the 10%, not the 100%.
  • The MCP interface changed how I use secrets entirely. A store my agents can call natively, with redaction built in, means the secure path is also the easy path. That's the only kind of security that survives contact with a busy workflow.
  • Self-hosting a secret store is worth the trust tax. There's something genuinely grounding about knowing your vault is a SQLite file on hardware you can walk over and touch, backed by code you've read line by line. The blast radius of a breach is a LAN, not a SaaS account.

Now when I add a new server, I add three keys to a file on my own box and forget about it. The vault nobody has to log into, the one that never asks me to rotate a workspace — that's the one I'll keep using.