Skip to content

JSLEEKR/envaudit

Repository files navigation

envaudit

License: MIT Python Tests Rules Type Checked Code Style

Audit environment variable configurations across .env, CI/CD, Docker, and Kubernetes for leaked secrets, cross-environment inconsistencies, and missing required variables.

Why This Exists

Environment variable configuration is the #1 source of production incidents that shouldn't happen. Secrets get committed in .env files. Variables exist in dev but are missing in prod. Debug flags stay enabled in production. Connection strings contain hardcoded credentials.

These problems are scattered across multiple file formats -- .env files, GitHub Actions YAML, GitLab CI configs, Docker Compose files, Kubernetes manifests, and shell scripts. No single tool audits them all together.

envaudit solves this by:

  • Parsing 6 different formats in a single scan
  • Running 25 rules across 5 categories (secrets, consistency, naming, security, best practices)
  • Outputting findings in text, JSON, or SARIF format for CI/CD integration
  • Providing diff mode to detect regressions between audit snapshots
  • Supporting configuration files for required variables, allowlists, and severity overrides

Installation

pip install envaudit

Or install from source:

git clone https://github.com/JSLEEKR/envaudit.git
cd envaudit
pip install -e .

Quick Start

Scan a single file

envaudit scan .env

Scan a directory

envaudit scan ./config/

Scan multiple paths

envaudit scan .env docker-compose.yml k8s/

JSON output for CI/CD

envaudit scan . --format json -o audit-results.json

SARIF output for GitHub Code Scanning

envaudit scan . --format sarif -o results.sarif

CLI Reference

envaudit scan

Scan environment variable files for issues.

envaudit scan <paths...> [OPTIONS]

Options:
  --format [text|json|sarif]   Output format (default: text)
  --config PATH                Path to envaudit.yaml config file
  --severity [error|warning|info]  Minimum severity to report (default: info)
  --env-name NAME              Environment name for scanned variables
  -o, --output PATH            Write output to file

Exit codes:

  • 0 -- No errors found
  • 1 -- One or more error-severity findings

envaudit diff

Compare two audit snapshots to detect regressions.

envaudit diff <old.json> <new.json> [OPTIONS]

Options:
  --format [text|json]  Output format (default: text)

Example workflow:

# Save baseline
envaudit scan . --format json -o baseline.json

# Make changes, then check for regressions
envaudit scan . --format json -o current.json
envaudit diff baseline.json current.json

Exit codes:

  • 0 -- No regression
  • 1 -- Regression detected (new errors or increased risk score)

envaudit rules

# List all rules
envaudit rules list

# List rules as JSON
envaudit rules list --format json

# Explain a specific rule
envaudit rules explain SEC001

envaudit config

# Create default envaudit.yaml
envaudit config init

# Validate a config file
envaudit config validate envaudit.yaml

Rule Catalog

Secret Detection (SEC)

Rule Description Severity
SEC001 Hardcoded password detected in value ERROR
SEC002 API key pattern detected in value ERROR
SEC003 Private key content detected in value ERROR
SEC004 Connection string with embedded credentials ERROR
SEC005 JWT token detected in value ERROR
SEC006 AWS access key pattern detected ERROR

Cross-Environment Consistency (CON)

Rule Description Severity
CON001 Variable present in one environment but missing in another WARNING
CON002 Variable value format differs across environments INFO
CON003 Required variable missing from environment ERROR
CON004 Variable defined but not referenced in other files INFO

Naming Conventions (NAM)

Rule Description Severity
NAM001 Mixed case variable name (not ALL_UPPER_SNAKE_CASE) INFO
NAM002 Variable name collision (same name, different casing) WARNING
NAM003 Reserved prefix used (AWS_, GITHUB_, CI_, etc.) INFO
NAM004 Variable name too short (< 3 characters) INFO
NAM005 Non-alphanumeric character in variable name WARNING

Security Best Practices (SRK)

Rule Description Severity
SRK001 Unencrypted secret in non-secret store ERROR
SRK002 Debug/development flag enabled in production config ERROR
SRK003 Overly permissive CORS origin (wildcard *) WARNING
SRK004 Insecure protocol (http://) in URL value WARNING
SRK005 Default/example credentials not replaced WARNING

Best Practices (BPR)

Rule Description Severity
BPR001 Empty value for environment variable INFO
BPR002 Duplicate key in the same file WARNING
BPR003 Commented-out variable with value (potential leak) INFO
BPR004 Sensitive variable without placeholder or secret reference WARNING
BPR005 Value contains interpolation syntax from wrong format WARNING

Supported Formats

Format File Patterns What's Parsed
.env .env, .env.*, *.env KEY=VALUE pairs, quoted values, export prefix
GitHub Actions .github/workflows/*.yml env: blocks at workflow, job, and step level; secrets references
GitLab CI .gitlab-ci.yml variables: blocks at top-level and job-level
Docker Compose docker-compose*.yml, compose*.yaml environment: as list or dict in services
Kubernetes *.yml with kind: ConfigMap|Secret|Deployment data, stringData, container env with value/valueFrom
Shell scripts *.sh, *.bash, *.zsh, shebang detection export KEY=VALUE statements

Configuration

Create an envaudit.yaml file to customize behavior:

version: "1"

# Define environments and their associated files
environments:
  - name: dev
    files: [".env.dev", "docker-compose.dev.yml"]
  - name: staging
    files: [".env.staging"]
  - name: prod
    files: [".env.prod", "k8s/prod/"]

# Required variables per environment
required_vars:
  all: [DATABASE_URL, APP_SECRET, LOG_LEVEL]
  prod: [SENTRY_DSN, NEW_RELIC_KEY]

# Rule configuration
rules:
  # Disable specific rules
  disable: [NAM004]
  # Override severity for specific rules
  severity_overrides:
    BPR001: warning

# Allowlist patterns
allowlist:
  # Variable name patterns to ignore (supports glob)
  variables: [PLACEHOLDER_*, TEST_*]
  # Known placeholder values to skip
  values: [changeme, your_value_here]

Using config in scan:

envaudit scan . --config envaudit.yaml

CI/CD Integration

GitHub Actions

name: Environment Audit
on: [push, pull_request]
jobs:
  envaudit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - run: pip install envaudit
      - run: envaudit scan . --format sarif -o results.sarif
      - uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: results.sarif

GitLab CI

envaudit:
  image: python:3.11
  script:
    - pip install envaudit
    - envaudit scan . --format json -o audit.json
  artifacts:
    reports:
      codequality: audit.json

Pre-commit Hook

#!/bin/bash
envaudit scan . --severity error

Output Examples

Text Output

envaudit scan results
Files scanned: 4 | Variables found: 23 | Risk score: 30.0

Severity  Rule      Variable             Message                                   File
ERROR     SEC001    DB_PASSWORD          Hardcoded password detected                .env:5
ERROR     SEC004    DATABASE_URL         Connection string with credentials         .env:3
WARNING   CON001    SENTRY_DSN           Missing in prod environment                -
WARNING   SRK003    CORS_ORIGIN          Wildcard '*' for CORS origins              .env.prod:8
INFO      NAM001    apiUrl               Not ALL_UPPER_SNAKE_CASE                   .env:12

Total: 5 findings (2 errors, 2 warnings, 1 info)

JSON Output

{
  "timestamp": "2026-04-12T10:00:00+00:00",
  "files_scanned": [".env", ".env.prod"],
  "variables_found": 23,
  "risk_score": 30.0,
  "findings": [
    {
      "rule_id": "SEC001",
      "severity": "error",
      "message": "Variable 'DB_PASSWORD' appears to contain a hardcoded password",
      "file": ".env",
      "line": 5,
      "variable": "DB_PASSWORD",
      "value_preview": "supe***",
      "remediation": "Use a secret manager or reference"
    }
  ]
}

Risk Score

The risk score (0-100) is calculated from findings:

Severity Points per finding
ERROR 10
WARNING 3
INFO 1

The score is capped at 100. A score of 0 means no findings.

Value Masking

envaudit never displays full secret values. Values are masked to show only the first 4 characters followed by ***. Values shorter than 5 characters are fully masked as ***.

Architecture

src/envaudit/
  cli.py            Click CLI entry point
  __main__.py        python -m envaudit support
  config.py          envaudit.yaml configuration (Pydantic v2)
  models.py          Core data models (EnvVar, Finding, AuditResult)
  scanner.py         Orchestrates parsing + rule evaluation
  diff.py            Diff mode for snapshot comparison
  parsers/           Format-specific parsers (6 formats)
  rules/             Audit rules (25 rules in 5 categories)
  output/            Output formatters (text, JSON, SARIF)

Development

# Clone and install
git clone https://github.com/JSLEEKR/envaudit.git
cd envaudit
pip install -e .

# Run tests
python -m pytest tests/ -q

# Type check
mypy --strict src/

# Lint
ruff check src/ tests/

License

MIT License - see LICENSE for details.

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Write tests for your changes
  4. Ensure ruff check and mypy --strict src/ pass
  5. Submit a pull request

About

Audit environment variable configs across .env, CI/CD, Docker, and K8s for secrets, inconsistencies, and missing variables — 25 built-in rules, SARIF output

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages