Sign inSign up

wahyouka/envaudit

By wahyouka

Updated about 1 month ago

Lint your environment & secret hygiene before it leaks

Image
Integration & delivery
Developer tools
1

117

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

about 2 months ago

docker pull wahyouka/envaudit