crypticenv
v0.1.0
Published
Git for your environment variables — versioned, encrypted, team-diffable, zero server required
Maintainers
Readme
CrypticEnv
Git for your environment variables — versioned, encrypted, team-diffable, zero server required.
What is it?
CrypticEnv treats .env files the way git treats code:
- Encrypted at rest — AES-256-GCM with a unique key per project
- Versioned — every change is a commit; roll back to any point in history
- Team-friendly — each member gets their own encrypted copy of the key (age X25519)
- Zero server — syncs through any private git repo you already have
- Diffable — see exactly which keys changed between any two versions
$ crypticenv set DATABASE_URL postgres://prod.example.com/mydb
✓ DATABASE_URL set [production]
$ crypticenv diff
abc1f2e3 → d8b9c012
~ DATABASE_URL
$ crypticenv run -- node server.js
# server starts with DATABASE_URL in its environment — never written to diskInstall
# One-time global install
npm install -g crypticenv
# or
pnpm add -g crypticenv
# Or run without installing
npx crypticenv initFive-second quickstart
cd my-project
crypticenv init # generates keypair, creates .crypticenv/
crypticenv set API_KEY sk-abc123 # encrypt and store
crypticenv get API_KEY # decrypt and print
crypticenv run -- node server.js # inject secrets into subprocess
crypticenv push # commit + push to your git remoteCore concepts
Environments
CrypticEnv creates three environments by default: development, staging, production. Each has its own encrypted bundle — staging secrets never leak into development.
crypticenv env list
crypticenv env switch production
crypticenv env create previewTeam sharing
Add a teammate with their age public key. CrypticEnv re-encrypts the bundle's data-encryption key (DEK) so they can decrypt secrets with their own private key.
# Alice generates her keypair on her machine
crypticenv init # (in any directory — just to generate the keypair)
cat ~/.crypticenv/keys/identity.age.pub
# Bob (project owner) adds Alice
crypticenv invite [email protected] age1qyqszqgpqyqszqgp...
# Alice can now pull and decrypt
crypticenv pull
crypticenv get DATABASE_URLRevoking access
When someone leaves the team, revoke their access. CrypticEnv generates a new DEK, re-encrypts all bundles for remaining members, and pushes. The revoked member's old wrapped key cannot decrypt the new bundles.
crypticenv revoke [email protected]Version history and rollback
Every push creates a versioned snapshot. Roll back to any point:
crypticenv log # show history
crypticenv diff abc1f2e3 d8b9c012 # compare two versions
crypticenv rollback abc1f2e3 # restore to that versionAll commands
| Command | Description |
|---------|-------------|
| init | Initialize a project and generate your age keypair |
| set <KEY> [value] | Encrypt and store a secret |
| get <KEY> | Decrypt and print a single secret |
| list | List all key names (no values) |
| delete <KEY> | Remove a secret |
| push | Commit encrypted bundle and push to remote |
| pull | Pull latest bundle from remote |
| run -- <cmd> | Run a command with secrets as env vars |
| export | Print export KEY=value for shell sourcing |
| env <subcommand> | Manage environments (list/switch/create/delete/rename) |
| log | Show version history |
| diff [a] [b] | Show what changed between versions |
| rollback <sha> | Restore a previous version |
| tag <name> | Tag the current version |
| invite <email> <pubkey> | Add a team member |
| revoke <email> | Remove a member and rotate the DEK |
| members | List project members |
| hook install | Install the git pre-commit secret scanner |
| scan [path] | Scan files for accidentally committed secrets |
| upgrade | Check for and install updates |
| tui | Launch the interactive terminal UI |
Run crypticenv <command> --help for full options on any command.
TUI
Run crypticenv (no arguments) or crypticenv tui to open the interactive terminal UI.
┌─ CrypticEnv ─────────────────────────── production ─┐
│ │
│ Secrets Environments History Team Diff │
│ │
│ DATABASE_URL ●●●●●●●●●●●●●●●●●●●● 2h ago │
│ REDIS_URL ●●●●●●●●●●●●●●●●●●●● 1d ago │
│ STRIPE_KEY ●●●●●●●●●●●●●●●●●●●● 3d ago │
│ │
│ [Space] reveal [n] new [d] delete [?] help │
└───────────────────────────────────────────────────────┘Keyboard shortcuts:
| Key | Action |
|-----|--------|
| s | Secrets screen |
| e | Environments screen |
| h | History screen |
| t | Team screen |
| d | Diff screen |
| ? | Help |
| q / Ctrl+C | Quit |
| Space | Reveal / hide selected secret value |
| n | New secret |
| Delete / d | Delete selected secret |
Security model
Encryption stack
| Layer | Algorithm | Parameters |
|-------|-----------|------------|
| Secret values | AES-256-GCM | 256-bit DEK, 96-bit IV, 128-bit auth tag |
| Key wrapping | age X25519 | One wrapped DEK per team member |
| Bundle integrity | HMAC-SHA256 | Over entire bundle JSON |
| Randomness | crypto.randomBytes | Never Math.random |
Six invariants, enforced in code
- Plaintext never to disk — values exist only in memory; buffers are zeroed after use
- Private key file = 0o600 — enforced immediately after keygen with
fs.chmod - Fresh IV every encryption —
crypto.randomBytes(12)insideencrypt(), never reused - Verify HMAC before decryption — tampered bundles are rejected before any decryption attempt
- DEK never logged — ESLint rule prevents logging variables named
*key*,*dek*,*secret* - Revoke = new DEK — revocation generates a fresh DEK and re-encrypts all bundles for remaining members
What CrypticEnv does NOT do
- Does not protect secrets that are already in your shell history
- Does not encrypt your git remote (use a private repo)
- Does not prevent a team member from copying secrets to their clipboard while they have access
Backend: local git (default)
CrypticEnv stores encrypted bundles on a separate crypticenv-data branch in your project's git repo. No external service is required.
# With a remote (recommended for teams)
crypticenv init --repo [email protected]:yourorg/your-repo-private.git
# Local-only (single machine)
crypticenv initGlobal config
CrypticEnv stores your keypair in ~/.crypticenv/keys/ (XDG-compliant).
~/.crypticenv/
keys/
identity.age ← private key (0o600)
identity.age.pub ← public key
config.json ← global settingsProject config lives at .crypticenv/config.json inside your project (safe to commit — no secrets here).
Environment variables
| Variable | Effect |
|----------|--------|
| CRYPTICENV_PRIVATE_KEY | Override path to private key file |
| CRYPTICENV_LOG_LEVEL | Set log verbosity (debug, info, warn, error) |
| NO_COLOR / CRYPTICENV_NO_COLOR | Disable ANSI color output |
Contributing
See CONTRIBUTING.md. Security issues → [email protected] (do not open a public issue).
License
MIT — free to use, modify, and distribute.
