Sign inSign up

wahyouka/envaudit

By wahyouka

•Updated 2 months ago

Lint your environment & secret hygiene before it leaks

Image
Integration & delivery
Developer tools
1

132

wahyouka/envaudit repository overview

⁠envaudit

Lint your environment & secret hygiene before it leaks.

envaudit is a small, zero-dependency CLI that audits a project's .env files for the mistakes that actually cause credential leaks:

  • Is the .env file actually covered by .gitignore?
  • Has it already been committed to git, ignore rule or not?
  • Are its file permissions too open (readable by other users)?
  • Do its values look like real secrets, or are they placeholders?

It's built to be dropped into a pre-commit hook or CI pipeline and fail fast, with no config required to get useful output.

⁠Install

go install github.com/sapiuwu/envaudit/cmd/envaudit@latest

Or clone and build locally:

git clone https://github.com/sapiuwu/envaudit
cd envaudit
go build -o envaudit ./cmd/envaudit

⁠Usage

envaudit scan                    # scan the current directory
envaudit scan ./backend          # scan a specific path
envaudit scan --format json      # machine-readable output
envaudit scan --no-strict        # always exit 0 (report only)
envaudit init                    # generate .envaudit.yml
envaudit install-hook            # install a pre-commit hook that runs the scan
⁠Example output
$ envaudit scan

envaudit v1.0.0 — scanning .

[CRITICAL]  .env                             file is tracked by git — run `git rm --cached .env` and rotate any secrets inside it
[HIGH]      .env:9                           AWS_ACCESS_KEY_ID looks like a real AWS Access Key ID (matches known pattern: AWS Access Key ID)
[HIGH]      .env:11                          ETH_PRIVATE_KEY looks like a real Ethereum/EVM Private Key (matches known pattern: Ethereum/EVM Private Key)
[MEDIUM]    .env                             file is writable by group members (mode -rw-rw-r--) — recommend chmod 600

Summary: 1 critical, 2 high, 1 medium, 0 low — 1 file(s) scanned

Exit code is non-zero whenever the highest finding meets or exceeds the configured severity_exit_code (default: high) — so envaudit scan can be dropped straight into CI or a pre-commit hook:

#!/bin/sh
# .git/hooks/pre-commit
envaudit scan || exit 1
⁠Install a pre-commit hook

The install-hook command does this for you and refuses to clobber an existing hook unless asked:

envaudit install-hook          # write .git/hooks/pre-commit
envaudit install-hook --force  # overwrite any existing hook

⁠Suppressing false positives (allowlist)

Real projects occasionally have .env files that must stay out of gitignore, or a value that looks like a secret but isn't. Instead of lowering severity_exit_code for everyone, add a per-file entry to .envaudit.yml:

allowlist:
  - file: deploy/.env          # silence a whole file
    rule: not-gitignored
  - file: .env
    line: 5                    # silence one line
  - file: .env
    key: AWS_ACCESS_KEY_ID     # silence a specific key

An entry suppresses a finding only when all the fields you set match, so the baseline stays precise.

⁠Why not just use gitleaks / trufflehog?

Those tools do deep, whole-repo secret scanning and are great at it. envaudit is narrower on purpose: it focuses specifically on .env hygiene — the gitignore/permissions/placeholder-vs-real-secret triage that happens before a secret ever gets scanned by something bigger. It's meant to be the fast, zero-config check that catches the most common mistake (a .env that was never gitignored, or already got committed) before you reach for a heavier tool.

⁠Configuration

Run envaudit init to generate .envaudit.yml:

rules:
  entropy_threshold: 4.0
  ignore_patterns:
    - "*.env.example"
    - "*.env.sample"
    - "*.env.template"
  custom_secret_patterns:
    - name: internal_service_token
      regex: "^svc_[a-zA-Z0-9]{32}$"
allowlist:
  - file: .env.example.deploy
    rule: not-gitignored
severity_exit_code: high
KeyDescriptionDefault
entropy_thresholdShannon entropy (bits/char) above which a value is considered random enough to be a real secret4.0
ignore_patternsFilename globs to skip entirely*.env.example, *.env.sample, *.env.template
custom_secret_patternsExtra regex rules, checked alongside the built-insnone
allowlistSuppress findings that match all of a given entry's fields (file, rule, line, key) — the checked-in baseline for accepted false positivesnone
severity_exit_codeMinimum severity (low/medium/high/critical) that causes a non-zero exithigh

file in an allowlist entry matches the full path or just the basename (e.g. .env), so baselines stay portable across machines and scan roots.

⁠How value classification works

For each KEY=VALUE pair in a .env file:

  1. Placeholder check — common stand-ins (changeme, your_api_key_here, <insert-key>, empty strings, ${VAR}-style templates) are ignored.
  2. Known pattern match — the value is checked against built-in regexes for AWS, Stripe, GitHub, OpenAI, Google, Telegram, Slack, JWTs, EVM private keys, database connection strings, and more. A match is high confidence regardless of entropy.
  3. Entropy + key-name heuristic — otherwise, the value's Shannon entropy is measured. High entropy in a key named *_SECRET, *_TOKEN, *_PASSWORD, etc. is flagged with a severity that scales with confidence.

This keeps false positives low — a placeholder like changeme is never flagged, but a stray real key almost always is.

⁠GitHub Action

envaudit ships as a Docker-based GitHub Action. Add this to .github/workflows/envaudit.yml in any repo you want scanned:

name: envaudit
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: sapiuwu/envaudit@v1
        with:
          path: "."          # optional, default "."
          strict: "true"      # optional, default "true"
          config: ".envaudit.yml"  # optional

See examples/consumer-workflow.yml⁠.

InputDescriptionDefault
pathDirectory to scan.
configPath to config file.envaudit.yml
strictFail the step on findings ≥ configured severitytrue
OutputDescription
findings-countTotal findings across all severities
highest-severityok, low, medium, high, or critical
exit-codeThe exit code envaudit produced

The action also writes a summary to the workflow run's Summary tab.

⁠Testing

go test ./... -v -cover
go vet ./...
gofmt -l .

This repo's own .github/workflows/ci.yml runs the full test suite and also dogfoods the action against itself on every push and PR.

⁠Versioning

envaudit follows Semantic Versioning⁠. Released versions are tagged vX.Y.Z and summarized in CHANGELOG.md⁠.

The version reported by envaudit version defaults to the latest release and is injected at build time by ./build.sh, which derives it from the nearest git tag. To pin a specific version:

go build -ldflags "-X main.version=1.2.3" -o envaudit ./cmd/envaudit

To cut a release:

# bump the version in CHANGELOG.md (move [Unreleased] to a new version),
# then tag and push the tag:
git tag -a v1.1.0 -m "envaudit v1.1.0"
git push origin v1.1.0

⁠Homebrew

envaudit ships as a Homebrew tap. Once the tap is set up:

brew tap sapiuwu/envaudit
brew install envaudit

The formula lives at contrib/homebrew/envaudit.rb⁠ and is regenerated automatically on every v* tag by .github/workflows/formula.yml, so its url/sha256 always match the latest release. To create the tap:

  1. Create a GitHub repository named homebrew-envaudit (same account/org as this project).
  2. Copy contrib/homebrew/envaudit.rb into it as Formula/envaudit.rb on the default branch.
  3. Done — brew install sapiuwu/envaudit/envaudit now works.

To refresh the formula locally for a specific version:

./scripts/update-formula.sh 1.1.0

⁠Roadmap

  • envaudit install-hook — one-command pre-commit hook installer
  • Baseline/allowlist file for accepted false positives
  • Publish to the GitHub Actions Marketplace
  • Homebrew tap

⁠Contributing

Issues and PRs welcome — especially new secret patterns (internal/rules/patterns.go) for services not yet covered.

⁠License

MIT — see LICENSE⁠.

Tag summary

Content type

Image

Digest

sha256:5a14dc5d1…

Size

11.9 MB

Last updated

2 months ago

docker pull wahyouka/envaudit