Stop Putting API Keys in .env Files — Use Your OS Keychain Instead
Source: Dev.to
The Problem in One Sentence
A developer at a YC startup accidentally pushed a .env file to a public GitHub repo. It contained:
- Stripe live key
- OpenAI API key
- Production database URL
Automated scanners found it in under 30 seconds. By the time GitHub’s secret‑scanning revoked the tokens, an attacker had already racked up $14 000 in OpenAI API charges.
How Common Is This?
| Metric | Value |
|---|---|
| New secrets exposed in public GitHub repos (2024) | 12.8 million |
| Year‑over‑year increase | +28 % |
| Private‑repo exposure | Worse – no public scanning |
Source: GitGuardian “2024 State of Secrets Sprawl” report.
Why .env Files Are Dangerous
The dotenv pattern (originating in Ruby, 2012) solved the problem of hard‑coding credentials in source code by moving them to a separate, .gitignore‑d file.
However, a typical developer’s .env today looks like this:
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...Issues:
- Plaintext – anyone with read access to the file can see the secrets.
- No authentication – any process running as your user (e.g., a rogue
npm postinstallscript, a compromised VS Code extension, a careless Docker build) can read the file silently. - No encryption at rest – the file is stored unencrypted on disk.
- No audit trail – you can’t tell which process accessed which secret.
- No expiry tracking – secrets linger long after they’re rotated.
Warning
The original.envassumption was that only your application would read the file. That assumption broke in 2025.
AI Coding Agents Amplify the Risk
AI assistants (Claude Code, Cursor, GitHub Copilot, Codex, etc.) routinely read every file in a project to build context. When they ingest a .env file:
The secret values become part of the model’s context window.
They can appear in generated code, debug output, error messages, or chat logs.
Even a well‑meaning assistant can leak credentials:
“Your
DATABASE_URLreturns connection refused” → the full URL ends up in the chat history, shared with teammates, logged by the provider, and potentially used as training data.
Bottom line: If a secret lives in a file an AI agent can read, assume it will be read.
A Better Approach on macOS: NoxKey + Keychain
The macOS Keychain is an encrypted credential store backed by the Secure Enclave and protected by Touch ID. NoxKey is a thin wrapper that makes the Keychain convenient for developers.
Before vs. After
| Before | After |
|---|---|
Plaintext .env file on disk | Secrets stored in Keychain, unlocked with Touch ID |
cat .env reveals all keys | noxkey get … prompts Touch ID, then injects the secret into the shell (never written to disk) |
Example Workflow
# Store a secret (Touch ID prompt)
$ noxkey set myorg/project/STRIPE_KEY --clipboard
✓ Stored myorg/project/STRIPE_KEY
# Load it into the current shell (Touch ID prompt)
$ eval "$(noxkey get myorg/project/STRIPE_KEY)"
# → secret now available as $STRIPE_KEY
$ echo $STRIPE_KEY
sk_live_51Hx...Features:
- One secret, one location – accessible from any project directory.
- No files on disk – the raw value never touches the filesystem.
- Touch ID on every access – ensures a human is present.
- AI‑aware – when an AI agent calls
noxkey get, NoxKey detects the agent’s process tree and returns an AES‑256‑CBC‑encrypted handoff instead of the raw value, keeping the secret out of the model’s context.
Agent calls noxkey get → Process tree detected → AES‑256‑CBC encryption → Secret in env, never in contextImport Existing .env Files
# Import all secrets from a .env file
$ noxkey import myorg/project .env
✓ Imported 5 secrets
# List what was imported
$ 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 (first 8 chars only)
$ noxkey peek myorg/project/STRIPE_SECRET_KEY
sk_live_...
# Finally, delete the insecure file
$ rm .envBulk Cleanup Example
# Find every .env file in ~/dev (excluding node_modules and .git)
$ find ~/dev -name ".env" -not -path "*/node_modules/*" -not -path "*/.git/*" | wc -l
47We imported 47
.envfiles in one afternoon using the command above.
Where Does This Fit in the Bigger Picture?
- Local development – NoxKey (or the OS‑native credential store) protects secrets on your laptop.
- CI/CD pipelines – Use platform‑specific secret stores: GitHub Actions secrets, Cloudflare environment variables, AWS Parameter Store, HashiCorp Vault, etc.
The current gap is the laptop‑side secret management. Replacing plaintext files with the OS credential store closes that gap.
Limitations & Considerations
- macOS‑only – NoxKey works on macOS. Linux and Windows teams need an equivalent solution (e.g., Gnome Keyring, Windows Credential Manager).
- Friction – Touch ID on every access adds a small authentication step.
- You can reduce prompts with
noxkey unlock myorg/project, which authenticates once per session. - Still more secure than the zero‑authentication model of
.envfiles.
- You can reduce prompts with
TL;DR
- Plaintext
.envfiles are a liability – they expose secrets to anyone (or any process) that can read the file. - AI agents exacerbate the risk – any file they can read may leak into model context.
- Replace
.envwith OS‑level credential stores (macOS Keychain + NoxKey, or equivalents on other OSes). - Import existing
.envfiles, delete them, and adopt the new workflow for all projects.
Secure your development environment today before the next “$14 k in API charges” story becomes your reality.
Why .env Files Are Insecure
- No encryption – the values are stored in plain text.
- No authentication – any process that can read the file can see the secrets.
- No access control – every AI agent, rogue script, or accidental
git pushcan expose the data.
12.8 million secrets were exposed in public repos last year. AI agents now read every file in your project directory. Supply‑chain attacks target plaintext credentials. The
.envpattern was a good idea in 2012; it’s a liability in 2026.
The Better Way: macOS Keychain (via NoxKey)
Your operating system already provides an encrypted, hardware‑backed credential store with biometric authentication. Use it.
Key Takeaway
- Move secrets to the macOS Keychain – one secure location, Touch ID on every access, and AI agents never see raw values.
- Migration takes minutes per project.
Install NoxKey
brew install no-box-dev/noxkey/noxkey- Free – no account, no cloud; your secrets stay on your machine.
- Open source – see the repo on GitHub.
How NoxKey Works
NoxKey wraps the Keychain in a developer‑friendly CLI.
# Retrieve a secret and inject it into the environment
eval "$(noxkey get myorg/KEY)"This replaces the usual process.env.KEY usage.
Frequently Asked Questions
Why are
.envfiles insecure?
They lack encryption, authentication, and access control.What should I use instead of dotenv?
Store secrets in the macOS Keychain via NoxKey.Can AI agents read
.envfiles?
Yes—any file they can access is readable.How do I migrate from
.envto the macOS Keychain?# Install NoxKey (if not already installed) brew install no-box-dev/noxkey/noxkey # Import all secrets from your .env file into the Keychain noxkey import myorg .env # Delete the .env file after a successful import rm .envThe migration takes about a minute per project.
Resources
Update your workflow:
Instead of copying .env.example and manually filling values, run noxkey import once and use the eval commands. It took us a day to stop reaching for .env instinctively—now it’s a one‑minute task per project.