Stop Putting API Keys in .env Files — Use Your OS Keychain Instead

Published: (March 26, 2026 at 06:35 PM EDT)
7 min read
Source: Dev.to

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?

MetricValue
New secrets exposed in public GitHub repos (2024)12.8 million
Year‑over‑year increase+28 %
Private‑repo exposureWorse – 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:

  1. Plaintext – anyone with read access to the file can see the secrets.
  2. No authentication – any process running as your user (e.g., a rogue npm postinstall script, a compromised VS Code extension, a careless Docker build) can read the file silently.
  3. No encryption at rest – the file is stored unencrypted on disk.
  4. No audit trail – you can’t tell which process accessed which secret.
  5. No expiry tracking – secrets linger long after they’re rotated.

Warning
The original .env assumption 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_URL returns 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

BeforeAfter
Plaintext .env file on diskSecrets stored in Keychain, unlocked with Touch ID
cat .env reveals all keysnoxkey 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 context

Import 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 .env

Bulk 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
47

We imported 47 .env files 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 .env files.

TL;DR

  1. Plaintext .env files are a liability – they expose secrets to anyone (or any process) that can read the file.
  2. AI agents exacerbate the risk – any file they can read may leak into model context.
  3. Replace .env with OS‑level credential stores (macOS Keychain + NoxKey, or equivalents on other OSes).
  4. Import existing .env files, 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 push can 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 .env pattern 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 .env files 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 .env files?
    Yes—any file they can access is readable.

  • How do I migrate from .env to 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 .env

    The 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.

0 views
Back to Blog

Related posts

Read more »