secure-env-vars
v2.0.0
Published
Zero-cloud encrypted .env vaults by Cortlet.
Maintainers
Readme
⚡ secure-env-vars
Secure Env Vars v2 — zero-cloud encrypted .env vaults using local RSA identities.
No account. No hosted service. No secret dashboard. No internet required.
secure-env-vars lets you encrypt a plaintext .env file into a shareable .env.vault, then safely inject the decrypted secrets into a process at runtime.
secure-env-vars run node app.jsWhy secure-env-vars?
Most secret managers depend on cloud accounts, hosted workspaces, or centralized dashboards.
secure-env-vars is different:
- Zero cloud — secrets stay local.
- RSA identity based — access is granted through public keys.
- Team sharing — allow teammates without sharing private keys.
- Memory injection — run commands with secrets in
process.env. - No plaintext required at runtime —
.env.vaultis enough. - V2 vault format — authenticated AES-256-GCM payloads with RSA-OAEP key wrapping.
- Migration support — migrate older v1 vaults to v2.
- Key rotation — rotate vault encryption keys safely.
Part of the Cortlet software brand.
Install
Use directly with npx:
npx secure-env-vars --helpOr install globally:
npm install -g secure-env-varsThen use either command name:
secure-env-vars --helpor:
env-vault --helpQuick Start
1. Initialize a project
secure-env-vars initThis creates a starter .env if one does not already exist and updates .gitignore.
Example:
EXAMPLE_SECRET=change-me2. Lock your .env
secure-env-vars lockThis encrypts .env into .env.vault.
The vault can be committed to git. The plaintext .env should not be committed.
3. Run your app with secrets injected
secure-env-vars run node app.jsOr with separator syntax:
secure-env-vars run -- node app.jsBoth forms are supported.
Your app receives decrypted values through environment variables:
console.log(process.env.EXAMPLE_SECRET);The plaintext .env does not need to exist at runtime.
RSA Identity
secure-env-vars uses your local RSA identity.
By default, it looks for keys in:
~/.ssh/Common supported key names include:
id_rsa
id_rsa.pubIf you do not have RSA keys, generate a local RSA identity:
node -e "const crypto = require('node:crypto'); const fs = require('node:fs'); const path = require('node:path'); const os = require('node:os'); const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 4096, publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }); const sshDir = path.join(os.homedir(), '.ssh'); if (!fs.existsSync(sshDir)) fs.mkdirSync(sshDir, { recursive: true }); fs.writeFileSync(path.join(sshDir, 'id_rsa'), privateKey); fs.writeFileSync(path.join(sshDir, 'id_rsa.pub'), publicKey); console.log('Identity created at ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub');"Keep your private key private.
Team Access
Add a teammate using their public key:
secure-env-vars allow ./teammate_id_rsa.pub --label "Teammate"List authorized identities:
secure-env-vars listRevoke access:
secure-env-vars revoke "Teammate"You can also revoke by fingerprint:
secure-env-vars revoke SHA256:exampleFingerprintHererevoke removes an identity from future vault access. For stronger security after removing someone, rotate the vault key.
secure-env-vars rotateKey Rotation
Rotate the vault encryption key:
secure-env-vars rotateThis:
- Creates a backup.
- Decrypts the current vault using your identity.
- Generates a new AES vault key.
- Re-encrypts the payload.
- Re-wraps the new key for allowed identities.
- Writes the updated
.env.vault.
For older v2 vaults that do not store teammate public keys, use:
secure-env-vars rotate --current-onlyThen re-add teammates:
secure-env-vars allow ./teammate_id_rsa.pub --label "Teammate"Migration from v1 to v2
Migrate an older v1 vault:
secure-env-vars migrateThe migration command creates a backup first:
.env.vault.backup-...Then it rewrites .env.vault using the v2 format.
After migration, verify:
secure-env-vars status
secure-env-vars run node app.jsOnly the current identity is preserved during v1 migration. Re-run allow for teammates.
Health Checks
Check project status:
secure-env-vars statusRun diagnostics:
secure-env-vars doctorScan for plaintext secrets or risky env files:
secure-env-vars scanCommands
| Command | Description |
|:--|:--|
| init | Initialize project files and .gitignore. |
| lock | Encrypt .env into .env.vault. |
| unlock | Decrypt vault contents into a plaintext output file. |
| run | Run a command with vault secrets injected into memory. |
| allow | Add a public key identity to the vault. |
| list | List identities authorized for the vault. |
| revoke | Remove an identity from the vault. |
| status | Show vault/project status. |
| doctor | Run project and vault diagnostics. |
| scan | Scan for plaintext env files and secret-like values. |
| migrate | Convert older v1 vaults to v2. |
| rotate | Rotate the vault encryption key. |
Examples
Lock default .env
secure-env-vars lockUse a custom vault path
secure-env-vars lock --env .env --vault production.vaultRun with that custom vault:
secure-env-vars run --vault production.vault node app.jsUnlock to a temporary file
secure-env-vars unlock --out .env.unlockedPrint decrypted env content
secure-env-vars unlock --printBe careful with --print; it writes secrets to the terminal.
What gets committed?
Usually commit:
.env.vaultDo not commit:
.env
.env.local
.env.*.local
.env.unlockedsecure-env-vars init helps update .gitignore.
Security Model
secure-env-vars uses envelope encryption:
- A random AES-256 key encrypts the
.envpayload. - The payload is encrypted with AES-256-GCM.
- The AES key is wrapped for each allowed RSA public key.
- Each authorized identity can unwrap the AES key using its private key.
- Secrets are injected into the child process environment during
run.
Private keys are never stored in the vault.
V2 Vault Format
A v2 vault contains:
{
"version": 2,
"product": "Cortlet Env Vault",
"createdAt": "...",
"updatedAt": "...",
"identities": [
{
"id": "...",
"label": "...",
"publicKeyFingerprint": "SHA256:...",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----...",
"wrappedKey": "...",
"addedAt": "..."
}
],
"payload": {
"iv": "...",
"tag": "...",
"data": "..."
}
}The payload is authenticated. If the wrong key is used or the vault is modified incorrectly, decryption fails.
Development
Install dependencies:
npm installBuild:
npm run buildRun unit tests:
npm run test:unitRun all tests:
npm testPackage dry run:
npm pack --dry-runCurrent Test Coverage
The v2 test suite covers:
- crypto encryption/decryption
- strict base64 validation
.envparsing- v2 vault format validation
- vault service lock/decrypt/unlock
initallowrevokerunmigraterotatescandoctor
Design Philosophy
secure-env-vars is built for developers who want secret management without surrendering control to a hosted service.
The goal is simple:
local keys
local vaults
safe sharing
no cloud dependency
no bloatLicense
MIT
Built for the sovereign developer.
Part of the Cortlet software brand.
