I lost $3,000 in crypto to a phishing attack last week.
A friend's hacked account DM'd me a Zoom link. I clicked. Downloaded. Ran it. The "installer" was malware. Within minutes my hot wallet was drained.
But here's what was strange: not all of my wallets were touched. Several EOAs were untouched.
When I dug in, the difference was simple:
The wallets that survived had their private keys in macOS Keychain — locked behind OS authentication.
The wallet that got drained had its private key in a .env file. Plaintext. In a project directory.
The malware scanned my disk for SECRET/KEY patterns and grabbed everything in seconds.
This is the difference between "secure" and "convenient." And we all do it. PRIVATE_KEY=, DATABASE_URL=, STRIPE_KEY= sitting in plaintext .env files because .gitignore covers us. Until it doesn't.
So I built senv — an encrypted .env replacement, written in Rust.
• Same workflow: `senv -- cargo run`, `senv -- npm dev`
• Private key in OS Keychain (TouchID-locked on macOS)
• Vault encrypted with age (X25519 ChaCha20-Poly1305)
• Single 2.5MB binary, no runtime
• Full TUI for editing multi-recipient team sharing
• Open source, MIT/Apache-2.0
The model is dead simple:
`senv init` → mint an age keypair, private → Keychain, public → .env.age
`senv import .env` → encrypt every value
`senv -- <cmd>` → decrypt in memory only, inject to child process
That's it. No more plaintext keys on disk.
If you keep API keys, DB creds, or wallet private keys in .env files — encrypt them. Use senv, SOPS, 1Password CLI, dotenvx — anything. Just don't leave plaintext on disk.
Repo:
github.com/gtg7784/senv
Docs: English, 한국어, 日本語, 中文