AI Agent Overwrote .env / Environment Variables

Agent rewrote .env with placeholders or removed entries — recover and prevent.

You open .env to run the project and every API key is now your_api_key_here, xxx, or replace_me — Claude Code, Cursor, or Aider, during a “clean up the project” or “fill in the .env template” pass, wiped your real secrets. Or worse: it deleted .env entirely, git wasn’t tracking it, and there’s no local backup. This happens weekly because agents default to treating .env as a template rather than real values. This article covers recovery first, then how to hard-lock the file so the agent never touches it again.

Common causes

Ordered by hit rate, highest first.

1. .env is gitignored, so the agent thinks it’s empty or missing

The number-one cause. .env is in .gitignore, so the agent can’t see contents via git. It reads .env.example full of placeholders, decides to “complete” the missing .env, and overwrites your real values.

# agent's "completion"
OPENAI_API_KEY=your_openai_api_key_here
DATABASE_URL=postgres://user:password@localhost:5432/db
STRIPE_SECRET_KEY=sk_test_xxxxxxxxxx

How to spot it: Open .env. If every value is your_xxx_here / xxx / textbook example data, this is it.

2. Agent “completed” example values for thoroughness

You asked it to “add a new env var REDIS_URL.” It rewrote the whole file in passing, replacing every existing value with example defaults. It thought this was “tidier.”

How to spot it: ls -la .env shows a fresh mtime even though git can’t diff it.

3. Editor extension or formatter rewrote on save

Some VS Code dotenv extensions “prettify” .env on save — quote values, align =, sort alphabetically. Some buggy versions blank values entirely. When Cursor’s agent saves the file, those extensions also fire.

How to spot it: Disable dotenv extensions, ask the agent to edit again, see whether it still mutates.

4. Agent confused .env with .env.example

It meant to update .env.example (commit the template) but the command had the wrong path and overwrote .env (your real values) with the template content.

How to spot it: Check the agent’s recent Write tool calls — target path .env or .env.example?

5. Agent ran a “generate .env” script

It ran cp .env.example .env, or a project-provided npm run setup script that unconditionally overwrites.

How to spot it: Search the agent’s command history for cp .env, mv .env, > .env, npm run setup, init.

6. Multi-worktree / multi-machine confusion

Agent was working in a worktree or sub-directory and created a new .env (empty template). When you switched back, the IDE picked up that one.

How to spot it: find . -name ".env*" -not -path "./node_modules/*" — multiple .env files mean confusion.

Shortest path to fix

Ordered by priority. Step 1 is recovery, Steps 2-5 prevent recurrence.

Step 1: Restore from backup / password manager / deploy platform

Try these sources in order of success rate:

SourceCommand / action
macOS Time Machinetmutil restore /Users/you/project/.env
Git stash (if you stashed before)git stash list then git stash show -p stash@{0}
1Password / Bitwarden / company password managerLook for the saved secret entry
Vercel / Netlify / Railway env panelProject Settings → Environment Variables → copy
Last screenshot shared on team Slack / NotionSearch chat history
~/.zsh_history / shell historygrep -i "API_KEY=" ~/.zsh_history for past exports
IDE recent files / Cursor / VS Code TimelineRight-click .env → Timeline / Local History

VS Code’s Local History (workbench.localHistory.enabled) is on by default and auto-saves every change — the most-overlooked but most-effective recovery source.

Step 2: Add agent ignore files alongside .gitignore

Different agents use different filenames. Cover all of them:

# .cursorignore  (Cursor)
.env
.env.local
.env.*.local

# .claudeignore  (some Claude Code versions)
.env*

# .aiderignore  (Aider)
.env
.env.*

# .gitignore  (keep this too)
.env
.env.local

This makes the agent unable to read .env in the first place, cutting off its ability to “complete” it.

Step 3: Hard-lock the rule in CLAUDE.md / AGENTS.md / .cursorrules

## File protection

- `.env` and `.env.*` (except `.env.example`) must never be read, edited, deleted, or overwritten
- To add a new env var, update only `.env.example` and list the new keys in the PR description
- Any "clean up project," "standardize config," or "fill in .env" request requires explicit user confirmation
- Real user secrets must never appear in agent output

Paste this into the project root instruction file. Claude Code, Cursor, Aider, and Codex all read these files every turn.

Step 4: Commit a safe .env.example

Give the agent a legal target so it doesn’t go for the real .env:

# Generate template from real .env (values stripped)
sed -E 's/=.*/=/' .env > .env.example
git add .env.example
git commit -m "chore: add .env.example template"

Future “add a new env var” requests update .env.example; you sync to .env by hand.

Step 5: Pre-commit hook against accidental commits

Even if the agent tries to commit .env, the hook stops it:

# .git/hooks/pre-commit  (or via husky)
if git diff --cached --name-only | grep -qE '^\.env(\.|$)' | grep -v '.env.example'; then
  echo "ERROR: refusing to commit .env file"
  exit 1
fi

For full coverage, use git-secrets or gitleaks to scan for secret patterns (sk_live_*, AKIA*, -----BEGIN PRIVATE KEY-----) — catches the case even if the filename changes.

Prevention

  • List .env* in both .gitignore and every agent’s ignore file (.cursorignore, .aiderignore, .claudeignore)
  • In CLAUDE.md / AGENTS.md / .cursorrules, write an explicit “never touch .env” rule with concrete paths
  • Store real secrets in a password manager (1Password / Bitwarden) — never only in a local .env
  • Periodically back up .env to an encrypted location — macOS Vault, an age-encrypted private git repo, or a company secret manager
  • Commit a .env.example template so the agent has a legitimate target for additions
  • Use pre-commit hooks plus gitleaks / git-secrets to block .env from entering git
  • When switching to a worktree or sub-directory, double-check which .env you’re editing — avoid having multiple copies

Tags: #AI coding #Debug #Troubleshooting