Last year, a developer at a YC startup pushed a .env file to a public GitHub repo. It contained their Stripe live key, an OpenAI API key, and a production database URL. Automated scanners picked it up in under 30 seconds. By the time GitHub's secret scanning revoked the tokens it recognized, someone had already racked up $14,000 in OpenAI API charges.
This is not rare. GitGuardian's 2024 State of Secrets Sprawl report found 12.8 million new secrets exposed in public GitHub repositories in a single year. A 28% increase from the year before. And those are just the public repos — private ones are worse, because nobody is scanning them.
12.8M
secrets exposed in public repos (2024)
28%
increase year over year
Your .env file is a liability. Here is why, and what to do about it.
The dotenv pattern was never a security mechanism
The dotenv pattern came out of the Ruby community in 2012. It solved a real problem: developers were hardcoding database passwords and API keys directly into source files. Moving them to a separate file that you .gitignore was a genuine improvement.
But here is what a typical .env looks like on a developer's machine right now:
OPENAI_API_KEY=sk-proj-abc123...
STRIPE_SECRET_KEY=sk_live_...
DATABASE_URL=postgresql://admin:password@prod-db.example.com:5432/main
CLOUDFLARE_API_TOKEN=v4x...
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI...
Five production credentials. Plaintext. No authentication to read them. No encryption at rest. No audit trail. Any process running as your user — a rogue npm postinstall script, a compromised VS Code extension, a careless docker build — can read that file without you knowing.
That is not security. That is a Post-it note on your monitor with the vault combination.
Why .env file security breaks down at scale
A single .env file is manageable. Nobody has a single .env file.
We counted ours. 47. Some in active projects, some in archived repos, some in Docker contexts that got copied into images. The same Cloudflare API token appeared in six different files. When we rotated it, we updated three and missed the other three for weeks. (Full story of that audit here.)
There is no expiry tracking. No way to know which secrets are still valid. No audit trail of which process read which key. When a breach happens, incident response starts with "wait, where do we even have this key?" and ends with grep -r across the entire home directory.
Warning
GitHub's push protection auto-revokes tokens from GitHub, AWS, Google Cloud, and a handful of other providers. But most services lack that integration. Your Stripe key, your Postmark token, your custom API credentials — if those hit a public repo, nobody revokes them automatically. You find out when the bill arrives or the data is gone.
AI agents turned .env files into a critical vulnerability
The .env pattern assumed that only your application would read the file. That assumption broke in 2025.
AI coding agents — Claude Code, Cursor, GitHub Copilot, Codex — routinely read project files to build context. Your .env is a project file. When an agent reads it, every secret in that file enters the model's context window. From there, values can appear in generated code, debug output, error messages, or conversation logs.
The agent is not being malicious. It is trying to help. "Here is the error — your DATABASE_URL returns connection refused" — and now your production database hostname and credentials are in the chat history. Shared with your team. Logged by the provider. Potentially used as training data.
We wrote more about specific leak vectors in 6 Ways AI Agents Leak Your Secrets. The short version: if a secret is in a file that an agent can read, assume it will be read.
The env file alternative: macOS Keychain with Touch ID
The macOS Keychain is an encrypted credential store that has been on every Mac for over 20 years. It is backed by the Secure Enclave, protected by Touch ID, and used by Safari, SSH, and every Apple-signed application. Not a startup's custom vault — infrastructure that Apple maintains and audits.
NoxKey is a thin layer on top of the Keychain, purpose-built for developer secrets:
Before: plaintext .env
# Plaintext file anyone can read
$ cat .env
STRIPE_SECRET_KEY=sk_live_51Hx...
After: Keychain + Touch ID
# Encrypted in Keychain, Touch ID on every access
$ noxkey set myorg/project/STRIPE_KEY --clipboard
✓ Stored myorg/project/STRIPE_KEY
$ eval "$(noxkey get myorg/project/STRIPE_KEY)"
# → Touch ID prompt → secret loaded into shell
# → raw value never written to disk
$ echo $STRIPE_KEY
sk_live_51Hx...
One secret, one location, accessible from any project directory. No files on disk. Touch ID every time. When an AI agent calls noxkey get, it detects the agent's process tree and returns an encrypted handoff instead of the raw value — the secret reaches the environment but never enters the conversation context.
Agent calls noxkey get → Process tree detected → AES-256-CBC encryption → Secret in env, never in context
Migrate from .env to Keychain in minutes
# Import your existing .env file
$ noxkey import myorg/project .env
✓ Imported 5 secrets
# Verify everything landed
$ noxkey ls myorg/project/
myorg/project/STRIPE_SECRET_KEY
myorg/project/OPENAI_API_KEY
myorg/project/DATABASE_URL
myorg/project/CLOUDFLARE_API_TOKEN
myorg/project/AWS_SECRET_ACCESS_KEY
# Peek at a value to confirm (shows first 8 chars)
$ noxkey peek myorg/project/STRIPE_SECRET_KEY
sk_live_...
# Now delete the liability
$ rm .env
Do that for every project. We did 47 in one afternoon. The find command that started it:
$ find ~/dev -name ".env" -not -path "*/node_modules/*" -not -path "*/.git/*" | wc -l
47
What about CI/CD?
This approach is for local development — your machine, your secrets, your Touch ID. CI/CD systems have their own secrets management: GitHub Actions secrets, Cloudflare environment variables, AWS Parameter Store, Vault. Those are purpose-built for that environment and they work.
The problem is the gap between "secrets managed in CI" and "secrets on your laptop." That gap is currently filled by plaintext files with no authentication, no encryption, and no access control. It should be filled by your operating system's credential store.
The honest tradeoffs of leaving dotenv behind
This is macOS only. If your team is on Linux or Windows, NoxKey is not the answer for them (though the principle holds — use your OS credential store, not plaintext files).
There is friction. Touch ID on every access means authenticating more than before. Session unlock (noxkey unlock myorg/project) reduces this to one authentication per batch, but it is still more than the zero authentication that .env offers. That friction is the point — it means something is actually guarding access.
You will need to update your workflow. Instead of copying .env.example and filling in values, you run noxkey import once and use eval commands. It took us about a day to stop reaching for .env instinctively.
Your API keys deserve better than plaintext files
12.8 million secrets exposed in public repos last year. AI agents reading every file in your project directory. Supply chain attacks targeting plaintext credentials. The .env pattern was a good idea in 2012. It is a liability in 2026.
Your operating system has an encrypted, hardware-backed credential store with biometric authentication. Use it.
Key Takeaway
Your .env file has no encryption, no authentication, and no access control. Every AI agent, every rogue script, and every accidental git push can read it. Move your secrets to the macOS Keychain — one location, Touch ID on every access, and AI agents never see the raw values. The migration takes minutes per project.
brew install no-box-dev/noxkey/noxkey
Free. No account. No cloud. Your secrets stay on your machine.
Frequently asked questions
*Why are .env files insecure?*
.env files store secrets as plaintext on disk with no encryption, no authentication, and no access control. Any process, script, or AI agent with file system access can read them. They frequently get committed to git — 12.8 million secrets were exposed on GitHub in 2024.
*What should I use instead of dotenv?*
Use your operating system's credential store. On macOS, the Keychain provides hardware-encrypted storage with Touch ID authentication. NoxKey wraps the Keychain in a developer-friendly CLI: eval "$(noxkey get myorg/KEY)" replaces process.env.KEY.
*Can AI agents read .env files?*
Yes. AI coding tools like Claude Code, Cursor, and Copilot have file system access and can read any .env file in your project directory. NoxKey prevents this by storing secrets in the Keychain and delivering them through encrypted handoff when an AI agent is detected.
*How do I migrate from .env to the macOS Keychain?*
Install NoxKey (brew install no-box-dev/noxkey/noxkey), then run noxkey import myorg .env to move all secrets to the Keychain. Delete the .env file afterward. The migration takes about a minute per project.
NoxKey is free and open source. brew install no-box-dev/noxkey/noxkey — GitHub | Website