How a 7-Person Startup Encrypted Their Secrets in One Sprint
Published March 30, 2026 · 7 min read · Case Study
The Starting Point
Picture a typical seed-stage startup: seven engineers, three environments (dev, staging, production), and a secrets strategy that could generously be described as "ad hoc." The staging database password lived in a Slack DM from six months ago. The production API keys were in a Google Doc that three people had bookmarked. Two developers had slightly different local .env files and nobody was quite sure which one was correct.
A contractor who had left two months earlier still theoretically had access to everything they had ever been messaged. Nobody had rotated the keys because nobody knew which keys they had.
This is not unusual. Most early-stage teams prioritize shipping over secret hygiene, and that is a reasonable tradeoff — until it isn't.
The Trigger
A senior engineer noticed that .env files were appearing in branches that contributors had pushed to forks. No secrets were exposed publicly — all the repos were private — but the close call was enough. The team decided to fix the problem properly before their Series A audit.
Requirements they agreed on:
- –Secrets must be encrypted before they touch version control.
- –Each developer should use their own key — no shared team password.
- –CI/CD must work without passing secrets through environment variable UI.
- –When someone leaves, their access must be revocable in under five minutes.
- –The solution cannot require a cloud account or subscription.
Day 1: Initialize and Encrypt
The lead engineer installed xenvsync via npm and ran the first encryption on the staging environment. Total time from reading the docs to a committed vault: eleven minutes.
.xenvsync.key was shared with the rest of the team over a secure channel (1Password) as a temporary measure. The team planned to move to per-member X25519 keys on Day 3.Day 2: Wire CI to Pull at Runtime
The team stored the staging key value in GitHub Actions Secrets and updated the pipeline to inject it at runtime. The plaintext environment variable blocks in the YAML were removed.
env: block from the pipeline YAML was the most satisfying part of the day. The pipeline went from 14 environment variables to two: the key and the passphrase.Day 3: Per-Member Keys and the V2 Vault
Each of the seven developers ran xenvsync keygen on their own machine and shared their public key with the lead. The lead added all seven to the team roster and re-pushed the vault. From that point on, everyone used their own identity to decrypt — the shared key from Day 1 was deleted and the locks changed.
Week 2: Standardize Across All Services
The team spent the second week rolling the same pattern out to their other three services. Each repo got its own vault. The shared V1 key for CI was replaced with the lead's own identity key injected from GitHub Secrets (since CI acts as a "robot team member" in their roster model).
They also set up the pre-commit hook from examples/hooks/pre-commit to prevent plaintext .env files from being staged accidentally — the problem that had triggered the whole migration.
The Offboarding Test
Three weeks after the migration, a contractor finished their engagement. The lead tested the revocation flow in a staging environment first:
Three Months Later
The team ran the migration past their Series A security audit. The auditor flagged the use of AES-256-GCM with fresh nonces, Git-committed encrypted vaults, per-member key isolation, and a documented rotation workflow as positives. The pre-existing shared-key approach was noted as resolved.
Developer feedback after three months was uniformly positive. The daily workflow — git pull, xenvsync pull, xenvsync run -- npm start — became muscle memory within a week. The pre-commit hook caught two accidental staging attempts in the first month, both from developers who had forgotten to push their vault after editing .env.