DEV Community

ke jia
ke jia

Posted on

dotguard vs GitHub Secret Scanning: What Each One Actually Catches

Every repo on GitHub gets secret scanning for free now. So why do I still run a local scanner on every project?

Short answer: they're scanning for different things, at different times, with different rules. Long answer: I ran the same test suite through both and mapped exactly where each one succeeds and fails. Here's the map.

The test

A fixture directory with 12 env files covering the usual suspects: hardcoded passwords, Stripe test and live keys, GitHub tokens, AWS access keys, JWT secrets, database URLs, private keys, and a few decoys (long strings that are not secrets — UUIDs, build hashes, base64-encoded public config).

Where GitHub's scanner wins

1. It scans history, not just the current tree. If the key was committed three months ago and deleted last week, GitHub's push protection and history scanning can still flag it. A file scanner on the working tree sees a clean repo and says "nothing here." This is the single biggest structural advantage, and it's the reason the free scanner is non-negotiable — it's the only one of the two that reaches into the past.

2. It knows provider-specific key formats. GitHub tokens (ghp_, gho_), AWS key IDs (AKIA...), Google API keys — the built-in patterns for your platform's own credential formats are well tuned, because the platform has a direct interest in its own keys not leaking.

3. It's already on. No setup, no CI step, no per-repo configuration. For a repo that's only ever on GitHub, it's the floor, and the floor is better than nothing.

Where the local scanner wins

1. Timing: it runs before the push. GitHub's push protection blocks at push time — the commit has already been made, the object has already been created locally, and in some configurations the block is a warning you can bypass. dotguard runs in pre-commit or CI before anything exists. The secret never becomes a git object in the first place.

2. It works anywhere. Internal GitLab, Gitea, bare mirrors, a repo synced to a local-only team server — the GitHub scanner simply isn't there. For the roughly half of my projects that live off-GitHub (client work, internal tooling, air-gapped environments), the local scanner is the only scanner.

3. It targets the env-file class specifically. GitHub's scanner is a general-purpose pattern matcher across all file types. dotguard is narrow on purpose: it walks every .env* file (recursively, skipping node_modules and hidden directories), matches against secret-shaped values, and — this is the part I like — it also checks for missing expected variables like NODE_ENV and PORT. No general-purpose scanner flags a missing variable. That check has caught more real deploy breakage than it has caught secrets.

4. The output is built for CI gates. GitHub's finding is a dashboard item you have to go look at. dotguard's output is a terminal report with an exit code — 1 means fail the build, full stop.

$ npx @wuchunjie/dotguard .

  .env (3 issues)
    L  1 | Hardcoded password
       DB_PASSWORD=***
    L  2 | API key
       STRIPE_API_KEY=***
    L  5 | Database URL
       DATABASE_URL=postgres://user:***@localhost:5432/app

  3 potential secrets exposed!
Enter fullscreen mode Exit fullscreen mode

The honest overlap

On a GitHub repo, a .env with a sk_live_ key gets caught by both, probably at slightly different times. The overlap is real. What's not overlapping is:

  • Off-GitHub repos: only the local scanner.
  • Pre-push prevention: only the local scanner.
  • History: only GitHub (or a dedicated history tool — I'll write about that separately).
  • Missing-variable checks: only the local scanner.

How I actually layer them

  1. dotguard in pre-commit — stops my own commits.
  2. dotguard in CI — stops PRs from forks and other machines, fails the build red.
  3. GitHub push protection on — catches what slips through, and scans history.
  4. Quarterly history scan — the catch-up for anything that predates the controls.

Each layer is cheap. The combination is the thing that actually closes the gap. And the local one is the only one you can point at a repo on a laptop that's never seen GitHub, which is where my client work lives.

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)