whisper-secrets
A zero-knowledge .env secret manager for teams
Stop sending API keys over Slack. Stop sharing .env files on Google Drive.
whisper-secrets encrypts your secrets on your machine before anything touches the network.
The server only sees ciphertext — no accounts, no signup, just a passphrase.
Install
Shell (macOS Apple Silicon / Linux)
curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/quentinved/Whisper/main/install.sh | sh
npm
npm install -g whisper-secrets
Download binary
Pre-built binaries for Linux (x64, arm64), macOS (Apple Silicon only — Intel Mac not supported), and Windows (x64) are available on the GitHub Releases page.
Quick Start
Choose the path that fits your situation:
Starting a new project
# 1. Generate a config with a random passphrase
# You'll get a Whisper link to share with your team
whisper-secrets init
# 2. Push your first secret (value is prompted, never in shell history)
whisper-secrets push DATABASE_URL
# 3. Teammates clone the repo, cd into it, then join (auto-pulls secrets)
whisper-secrets join <link-from-teammate>
Already have a .env?
# 1. Set up your config
whisper-secrets init
# 2. Upload every entry from your existing .env
whisper-secrets import
# 3. Commit .env.whisper to your repo (it only contains UUIDs, no secrets)
# 4. Teammates clone the repo, cd into it, then join (auto-pulls secrets)
whisper-secrets join <link-from-teammate>
.env.whisper maps variable names to server-side UUIDs — no secrets in it.
Commit it to your repo. Keep .whisperrc in your .gitignore.
Commands
init
Create a .whisperrc config with a randomly generated passphrase.
A Whisper link (expires in 24h) is created automatically — send it to your team.
whisper-secrets init
whisper-secrets init --url http://localhost:1212
whisper-secrets init --manual-passphrase
join
Join a project using a Whisper share link from a teammate. Fetches the passphrase, creates your .whisperrc, and auto-pulls secrets if .env.whisper exists. Run this from within the cloned repo directory.
whisper-secrets join https://whisper.quentinvedrenne.com/get_secret?shared_secret_id=...#k=<key>
Paste the whole link. The #k=<key> fragment carries the decryption key and never reaches the server — strip it and the secret can't be decrypted.
invite
Generate a new share link to invite a teammate. Re-shares the passphrase from your .whisperrc (expires in 24h).
whisper-secrets invite
import
Read your existing .env and push every entry. Entries already tracked in .env.whisper are skipped.
whisper-secrets import
push
Encrypt and upload a single secret, or pick from untracked .env entries interactively.
whisper-secrets push DATABASE_URL # push a specific secret (prompts for value)
whisper-secrets push # pick from untracked .env entries
pull
Download and decrypt every secret listed in .env.whisper into .env.
Tracked entries are updated in place, missing ones are added, and your local-only entries and comments are kept.
If a local value would change, pull lists the names and asks first — --yes skips the question (CI, scripts, AI agents).
whisper-secrets pull
whisper-secrets pull --yes
run
Run any command with your secrets injected as environment variables. Nothing is written to disk: no .env left behind, and values that don't fit in a .env (multi-line keys, certificates) just work. On macOS and Linux the command takes over the process, so Ctrl+C and signals from Docker or CI reach it directly, and its exit code is passed through.
whisper-secrets run -- npm start
whisper-secrets run -- cargo test
whisper-secrets run -- docker compose up
rotate
Update a secret in-place — same UUID, new encrypted value.
whisper-secrets rotate DATABASE_URL
remove
Delete a secret from the server and remove it from .env.whisper and .env.
whisper-secrets remove OLD_API_KEY
status
Show the current state of your secrets: what's tracked, what needs a pull, and what's untracked in .env.
whisper-secrets status
share
Create a one-time secret link, just like the Whisper web UI. Defaults to 1 hour, self-destructs after first view.
whisper-secrets share
whisper-secrets share -e 24h
whisper-secrets share -e 7d --no-self-destruct
get
Retrieve a shared secret from a Whisper link or ID, straight from your terminal.
whisper-secrets get https://whisper.quentinvedrenne.com/get_secret?shared_secret_id=...#k=<key>
whisper-secrets get 550e8400-e29b-41d4-a716-446655440000
Keep the #k=<key> fragment on the link — it holds the decryption key and is required to read the secret.
Tip: If installed via npm or the shell installer, ws is available as a shortcut for whisper-secrets.
Use with AI coding agents
Stop being scared to share your .env with your team.
Install the whisper-secrets agent skill and your AI coding agent (Claude Code, Cursor, Codex, Copilot…) will offer to manage your project's .env with Whisper:
set it up, sync it with your team, and run your app and tests with whisper-secrets run, without ever seeing a secret value.
Claude Code
/plugin marketplace add quentinved/Whisper
/plugin install whisper-secrets@whisper
Cursor, Codex, Copilot and other agents
npx skills add quentinved/Whisper
Then open a project and ask something like “set up the env for this project” or “add a Stripe key”. The agent:
- works from secret names only (
whisper-secrets status,.env.whisper) and never reads.envor.whisperrc. In Claude Code, the plugin also blocks the agent's file tools from opening them (committed.envfiles stay readable), and in Cursor the skill offers to add them to.cursorignore; - runs
status,run,importandpullitself; - hands you the commands that take a hidden value or print your team's passphrase link (
init,invite,join,push,rotate,share) to run in your own terminal; - when it's done, offers to commit
.env.whisper(only if you want) and to add an “Environment setup” section to your README.
How It Works
- Your passphrase is stretched into a 256-bit key using PBKDF2-SHA256 (600 000 iterations). The passphrase never leaves your machine.
- Each secret is encrypted with AES-256-GCM using a unique random nonce. The server stores only ciphertext.
.env.whispermaps each variable name to a UUID on the server — no secrets, safe to commit.- When you
pull, the CLI fetches each UUID, decrypts locally, and updates.env.
The server is zero-knowledge: even if the database leaks, your secrets stay encrypted. Only someone with the passphrase can decrypt them.
Configuration
The .whisperrc file lives in your project root:
{
"url": "https://whisper.quentinvedrenne.com",
"passphrase": "your-team-passphrase"
}
passphrase— required, generated byinitor chosen with--manual-passphraseurl— optional, defaults tohttps://whisper.quentinvedrenne.com
Add .whisperrc to your .gitignore — it contains your passphrase.
CI/CD
Store the .whisperrc JSON as a CI secret, then write it to disk before pulling:
# GitHub Actions example
- name: Pull secrets
run: |
echo '${{ secrets.WHISPERRC }}' > .whisperrc
whisper-secrets pull
Or skip the .env file and inject secrets straight into the step's command:
- name: Test
run: |
echo '${{ secrets.WHISPERRC }}' > .whisperrc
whisper-secrets run -- npm test
Debugging
Use -v to see what's happening under the hood:
whisper-secrets -v push DATABASE_URL
FAQ
What happens if I lose the passphrase?
The secrets are gone. That's the zero-knowledge guarantee — nobody can recover them, not even us. Keep a backup in a password manager.
How do I onboard a new teammate?
- Run
whisper-secrets inviteto generate a new share link (or reuse the one frominitif still valid). - They clone the repo and
cdinto it (so.env.whisperis present). - They run
whisper-secrets join <link>— this creates.whisperrcand auto-pulls secrets.
A credential got leaked. Now what?
- Revoke the compromised key in the relevant service.
- Rotate the value:
whisper-secrets rotate LEAKED_KEY - Tell the team to
whisper-secrets pull.
Can my AI coding agent see my secrets?
Not if it uses the agent skill. The agent checks secret names with whisper-secrets status and runs your code with whisper-secrets run, which hands values straight to the process.
Commands that take or reveal a value are left to you, in your own terminal. Without the skill, agents often read .env to “check the config”, and every value they read ends up in the conversation.
Can I self-host?
Yes! Whisper is open source. Deploy the server anywhere and point the CLI at your instance:
whisper-secrets init --url https://your-whisper-instance.com
See the GitHub repo for setup instructions.