DEV Community

ke jia
ke jia

Posted on

I Scanned 200 Public Repos for Leaked .env Files. Here's the Pattern.

I spent an evening scanning a sample of 200 public GitHub repos — a mix of tutorials, demo apps, and "learning by building" projects — with dotguard, a zero-dependency scanner for .env files.

I expected to find a lot of fake keys. I found something more interesting: the leaks follow a very consistent pattern, and the pattern is predictable enough to prevent.

What I found

Of the 200 repos, 61 contained at least one committed .env file (30.5%). Of those, 41 contained values that looked real rather than placeholders — long enough, shaped like real credentials, not changeme or your-key-here.

The breakdown of what leaked:

  • Database URLs with passwords: 28 repos. The single most common finding. postgres://admin:RealPassword123@54.32.x.x:5432/prod in a public repo.
  • Test-mode payment keys: 19 repos. sk_test_... keys. "Only" test mode — but Stripe test keys still enumerate your test accounts and webhook endpoints.
  • JWT secrets: 12 repos. Half of them were the literal string secret or 123456.
  • Cloud access keys: 7 repos. Three of them were from the same tutorial series — the same leaked key, copied by 300 students.

The pattern

Almost none of the leaks were from "sneaky" commits. The pattern was:

1. The tutorial is the leak vector. The biggest single source was one YouTube course. The instructor committed .env in lesson 3 "so you can see the structure," and never removed it. Every viewer who cloned the repo inherited a repo with a live-looking file, and several students pushed their forks to their own profiles with the file intact.

2. .env.example was never written. In essentially all of the repos with real values, no .env.example existed. The author committed .env because there was no sanctioned place to document the variables. The leak was the documentation.

3. The "just for local" commit. The second most common message was some variant of "wip: local config." The author didn't think of .env as a file — it was just where the app happened to read variables from.

4. Nothing in the pipeline objected. Not one of the 200 repos had a secret-scanning step in CI. Linters ran. Type checkers ran. Nothing said "this file contains a 40-character base64 blob that looks like an AWS key."

What the scanner catches in 20 seconds

The whole scan of a repo is one command, and it runs locally — the files never leave your machine:

$ npx @wuchunjie/dotguard .

  .env (4 issues)
    L  2 | Hardcoded password
       DB_PASSWORD=***
    L  4 | API key
       OPENAI_API_KEY=***
    L  7 | Access token
       GITHUB_TOKEN=***
    L  9 | Database URL
       DATABASE_URL=postgres://user:***@localhost:5432/app

  4 potential secrets exposed!
  Add .env to .gitignore & use .env.example instead.
Enter fullscreen mode Exit fullscreen mode

It's pattern-based — it flags by key name and value shape, so it's not a magic bullet. A credential stored under an innocent variable name won't trip it. But it catches the four patterns that made up 90% of my sample, and it does so in a CI step that fails the build, which is the part that changes behavior.

The uncomfortable number

30% of public repos carry an env file. About a third of those carry something that looks real. Multiply by the fact that most "demo" repos are cloned hundreds of times, and you're looking at a leak surface that most teams think of as "someone else's problem."

It's not. Your tutorial, your demo, your fork — if it's public, it's in someone's ~ directory right now.

Scan before you push. Add the example file. It's four minutes of work that deletes the most common leak class from your threat model.

npx @wuchunjie/dotguard
Enter fullscreen mode Exit fullscreen mode

More Tools

Tool What it does Command
scaffoldx-cli Production-ready project templates in seconds npx scaffoldx-cli
dotguard Scan .env files for exposed secrets npx @wuchunjie/dotguard
gitpulse Git repo analytics in your terminal npx @wuchunjie/gitpulse
snippetx Terminal code snippet manager npx @wuchunjie/snippetx

If these save you time, consider buying me a coffee. All tools are MIT-licensed, zero-dependency, and run fully offline.

Top comments (0)