A simple command-line tool for managing encrypted project secrets stored in a single file.
- AES-256-GCM authenticated encryption
- Argon2id key derivation (brute-force resistant)
- Single encrypted vault file — safe to commit to version control
- Secrets are decrypted only in memory; the
editcommand attempts to keep plaintext off disk (using/dev/shmon Linux when available — see below) - Export secrets as environment variables (
eval "$(nillsec env)") - Run processes with injected secrets (
nillsec exec -- <command>)
Pre-built binary (macOS / Linux / Windows)
Download the archive for your platform from the latest release, then extract and install:
# macOS (Apple Silicon)
curl -L https://github.com/403-html/nillsec/releases/latest/download/nillsec-darwin-arm64.tar.gz | tar -xz
sudo mv nillsec-darwin-arm64 /usr/local/bin/nillsec
# macOS (Intel)
curl -L https://github.com/403-html/nillsec/releases/latest/download/nillsec-darwin-amd64.tar.gz | tar -xz
sudo mv nillsec-darwin-amd64 /usr/local/bin/nillsec
# Linux (x86-64)
curl -L https://github.com/403-html/nillsec/releases/latest/download/nillsec-linux-amd64.tar.gz | tar -xz
sudo mv nillsec-linux-amd64 /usr/local/bin/nillsecmacOS note: always extract with
tar -xzf(or pipe throughtar -xzas above) rather than double-clicking the archive in Finder. Extracting in the terminal prevents macOS from applying the quarantine flag to the binary, which avoids the "Apple could not verify…" Gatekeeper prompt.
Via Go toolchain
go install github.com/403-html/nillsec@latestBuild from source
go build -o nillsec .$VAULT;1
kdf: argon2id
salt: <base64>
nonce: <base64>
cipher: aes-256-gcm
data: <base64>
nillsec initnillsec add database_password super-secret
nillsec add api_token abcdefnillsec set database_password new-valuenillsec get database_password
# → super-secretnillsec list
# → api_token
# → database_passwordnillsec remove api_tokennillsec editSecurity note: The
editcommand temporarily exposes vault plaintext so that the editor can open it.
- Linux — the file is created in
/dev/shm, atmpfsmount backed entirely by RAM. The decrypted content never reaches a physical disk. If/dev/shmis unavailable or unwritable,nillsecfalls back to the OS temp directory.- Other platforms — a private temp file (
0600) is used in the OS temp directory. Its contents are zero-wiped and the file is deleted as soon as the editor exits.On all platforms the editor file is wiped and removed once the editor exits. If the file cannot be removed,
nillsecaborts and does not save the vault, so that plaintext is never silently left behind.
nillsec exec -- npm run devSecrets are injected as environment variables into the child process directly — no shell expansion occurs, so there is no risk of secret values being interpreted as shell code. Vault secrets take precedence over any identically-named variables already present in the environment.
nillsec exec -- python manage.py runserver
nillsec exec -- docker compose up
# Open a secure shell with all secrets available as env vars:
nillsec exec -- $SHELLThe -- separator is optional but recommended to clearly distinguish nillsec flags from the command being run.
If you need to export secrets into your current shell session rather than running a subprocess, use:
eval "$(nillsec env)"
# Sets DATABASE_PASSWORD and API_TOKEN in the current shell.nillsec upgradenillsec upgrade fetches the latest release from GitHub, replaces the running
binary in-place, and exits. If the latest release is a major version bump
(e.g. v1 → v2), you will be warned that breaking changes may be present and
asked to confirm before the download begins. If you are already on the latest
version, the command simply tells you so and exits without making any changes.
| Tool / approach | Encrypted at rest | Git-friendly | Export to env vars | Needs external service | Best fit |
|---|---|---|---|---|---|
| nillsec | ✅ | ✅ | ✅ | No | Local dev & small teams — encrypted secrets in Git with quick env export; separate master password to manage |
Plain .env |
❌ | ✅ | No | Prototypes and non-sensitive config; easy to leak | |
| direnv / dotenv | ❌ | ✅ | No | Convenient env auto-loading; still plaintext | |
| dotenvx | ✅ | ✅ | ✅ | No | .env-style workflow with added encryption; separate key to manage |
| Ansible Vault / SOPS / git-crypt | ✅ | ✅ | No | Encrypting files or whole repos; not optimised for env export | |
| OS keychain (envchain, Keychain) | ✅ | ❌ | ✅ | No | Workstation secrets in OS keystore; not portable across machines |
| Doppler / Infisical / 1Password CLI | ✅ | ❌ | ✅ | Yes | Centralised secret lifecycle with sharing, audit, and rotation |
| CI/CD secrets (GitHub Actions, etc.) | ✅ | ❌ | ✅ | Yes | Build and deploy pipelines; not local dev friendly |
| Vault / Kubernetes Secrets | ✅ | ❌ | Yes | Enterprise platform-level secret management; high complexity |
| Variable | Description | Default |
|---|---|---|
NILLSEC_VAULT |
Path to the vault file | secrets.vault |
NILLSEC_PASSWORD |
Master password (for scripting / CI use) | — |
EDITOR |
Editor used by the edit command |
vi |
nillsec init
nillsec add database_password secret
nillsec add api_token token123
# Run a command directly with secrets injected:
nillsec exec -- npm run dev
# Or open a shell with all secrets available:
nillsec exec -- $SHELL
# If you need the secrets exported into your current shell session:
eval "$(nillsec env)"
echo "$DATABASE_PASSWORD"