DEV Community

Anas Sheikh
Anas Sheikh

Posted on

You Deleted the .env File From Git. Your Secrets Are Still Public.

You notice it during a code review: .env is in the repository. Your stomach drops. You run git rm .env, commit with the message "remove env file", push, and feel the relief of a problem solved.

It is not solved. The file is gone from your latest commit. It is sitting, in full, in every commit before that one, and anyone who can read the repository can read it.

Why Deleting Doesn't Delete

Git is a history book. A new commit adds a page saying "the file no longer exists". It does not tear out the old pages.

git log --all --full-history -- .env
Enter fullscreen mode Exit fullscreen mode

If that prints any commits, your file is in history. And anyone can go back to it:

git show <old-commit>:.env
Enter fullscreen mode Exit fullscreen mode

That works for a public repository on GitHub, for a coworker's clone, for a fork, and for any tool that scans old commits. Automated bots scan public repositories for exactly this, so a leaked key can be found quickly.

Step 1: Rotate Everything First

This is the part people skip, and it is the only part that actually matters.

Treat every secret that was ever in that file as compromised, and replace it:

  • Database passwords and connection strings
  • API keys (payment, email, storage, maps, AI)
  • Auth secrets such as NEXTAUTH_SECRET or JWT signing keys
  • OAuth client secrets
  • Webhook signing secrets

Create the new value, update your hosting environment, deploy, and then revoke the old one. Cleaning the history comes after, because cleaning cannot take back what someone already copied.

Rotating a signing secret logs users out, which is the right outcome. It means the old secret can no longer be used to forge sessions.

Step 2: Find Out What Else Was Committed

.env is not the only way secrets end up in Git. Search the whole history for the values themselves:

git log -p --all -S'sk_live' | head -100
Enter fullscreen mode Exit fullscreen mode

-S finds commits where a string was added or removed. Try the prefixes of keys you use. A dedicated scanner is faster and more thorough:

gitleaks detect --source . --log-opts="--all"
Enter fullscreen mode Exit fullscreen mode

It checks every commit for patterns that look like keys and tokens, and prints where it found them.

Step 3: Remove It From History

Once the secrets are rotated, you can clean the history so the old file stops being a trap. The current recommended tool is git filter-repo:

git filter-repo --path .env --invert-paths
Enter fullscreen mode Exit fullscreen mode

This rewrites every commit as if .env had never been added. Because it changes commit IDs, you then force push:

git push --force --all
Enter fullscreen mode Exit fullscreen mode

Be honest about the limits:

  • Everyone else must re-clone or reset, or they will push the old history back.
  • Forks and existing clones keep the old data. You cannot reach into them.
  • Hosting platforms may keep cached copies of old commits for a while. Check their guidance on removing sensitive data.

This is why step 1 comes first. History rewriting is cleanup, and rotation is the fix.

The Leak That Has Nothing to Do With Git

Next.js developers have a second way to leak a secret, and no commit is involved:

# .env.local
NEXT_PUBLIC_STRIPE_SECRET_KEY=sk_live_...
Enter fullscreen mode Exit fullscreen mode

Any variable that starts with NEXT_PUBLIC_ is inlined into the JavaScript sent to the browser at build time. Anyone can open DevTools, read your bundle and find the value. The prefix means "this is safe to publish", and it does exactly that.

Rules that keep you safe:

  • Only values that are meant to be public get the NEXT_PUBLIC_ prefix, such as a public analytics ID or a publishable key.
  • Secret keys have no prefix and are read only in Server Components, Route Handlers and Server Actions.
  • If a secret ever got that prefix, assume it is exposed and rotate it.

Make It Hard to Repeat

Ignore the file before the first commit.

.env
.env.*
!.env.example
Enter fullscreen mode Exit fullscreen mode

Commit a .env.example with the variable names and fake values, so teammates know what to set, and nothing real is ever in the repository.

Scan before commits leave your machine. A pre-commit hook with a scanner like gitleaks blocks a commit that contains something key-shaped. Hosting your code on GitHub also gives you secret scanning and push protection for many known key formats. Turn both on.

Fail loudly when a variable is missing. Check required variables at startup, so a missing secret becomes an error message, not a silent fallback to a hardcoded value that someone then commits.

The Rule

Once a secret has been in a commit, it is public forever. The fix is rotation, not deletion. Rotate first, clean the history second, and add a scanner so the next mistake is caught before it leaves your laptop.

Quick audit, right now, in your own project:

git log --all --full-history -- .env .env.local .env.production
Enter fullscreen mode Exit fullscreen mode

If that prints anything, you have found a rotation task.

If you are starting a new Next.js project and want the structure set up sensibly from day one, you can browse my templates on pixelanas.com.

Get the templates: https://pixelanas.gumroad.com

Have you ever committed a secret by accident, and how fast did you notice? Tell me in the comments, and no judgment, this happens to nearly everyone once.


Anas, full-stack Next.js developer building SaaS products and premium templates. X: @ASheikh69751

Top comments (0)