Skip to main content
hooksSource-backedReview first Safety Privacy

Environment Validator

Validates environment variables, checks for required vars, and ensures proper configuration across environments.

by JSONbored·added 2025-09-16·
HarnessClaude Code
Trigger:PostToolUse
Review first review before installing

Open the source and read safety notes before installing.

Citation facts

Source-backed facts for citing this resource, derived directly from the registry — also available as plain text for AI assistants.

Source URLs
https://code.claude.com/docs/en/hooks, https://github.com/JSONbored/awesome-claude/blob/main/content/hooks/environment-variable-validator.mdx
Safety notes
Runs automatically on its configured Claude Code hook event and executes shell logic that can read, modify, or delete files in your project (and may run builds, installs, or network calls); review the script and scope it to expected paths before enabling.
Privacy notes
Receives Claude Code hook input (session metadata, file paths, and tool output) and reads local project files; review what the script logs or forwards to external services and keep credentials out of its output.
Author
JSONbored
Claim status
unclaimed
Last verified
2025-09-16

Decision playbook

Review trust signals before you adopt

Signals are present but mixed. Use the checklist below to confirm the source and operational safety for your environment.

Compare context
Selected

0

Current score

78

Baseline

Delta

No baseline selected

No major trust-signal divergence detected in the current selection.

Source and provenance checks

Complete

Confirm ownership and provenance before trusting install instructions.

  • Source link availableRequired

    Open the canonical repository and verify ownership.

    Done
  • Source provenance statusRequired

    Marked as source-backed.

    Done
  • Metadata reviewed

    Registry metadata indicates a reviewed listing.

    Done

Safety and privacy checks

Complete

Validate risk disclosures before installation or API wiring.

  • Safety notes presentRequired

    Review the listed safety guidance before running commands.

    Done
  • Privacy notes presentRequired

    Review data handling notes before connecting accounts or secrets.

    Done
  • Trust level risk gateRequired

    Trust level does not block evaluation.

    Done

Package and install checks

Needs review

Check package metadata and artifact integrity signals.

  • Install payload available

    Install or copy payload is available for review.

    Done
  • Package verification flag

    No package verification flag provided.

    Pending
  • Checksum metadata

    No checksum provided for downloaded artifact.

    Pending

Compare-driven decision checks

Needs review

Use compare context to validate trade-offs before adoption.

  • Compare tray has multiple entries

    Add at least one more entry to compare trust differences.

    Pending
  • Baseline comparison available

    No baseline peer selected yet.

    Pending
  • Diverging trust signals identified

    No major trust-signal divergence found.

    Pending

Setup at a glance

CLI install

Copy-ready — paste the snippet to get started.

Install command

Provided

Config snippet

Provided

Copy snippet

Provided

Prerequisites

None

Platforms

1 listed

Difficulty

0/100

Adoption plan

Balanced adoption plan

Current risk score 16/100. Use staged verification before broader rollout.

Risk 16

Pre-adoption checks

Validate source and review signals before any execution.

  • Confirm source provenanceRequired

    Source URL/provenance metadata is present.

    Done
  • Confirm metadata review state

    Listing has review metadata.

    Done
  • Verify install payload

    Install/config payload exists and can be inspected.

    Done

Security checks

Confirm safety, privacy, and package integrity signals.

  • Review safety notesRequired

    Safety notes are present.

    Done
  • Review privacy notesRequired

    Privacy notes are present.

    Done
  • Verify package integrity metadata

    No package verification/checksum metadata.

    Pending

Rollout

Adopt in controlled steps based on the selected plan.

  • Run in isolated sandbox firstRequired

    Use a constrained sandbox and observe behavior across multiple tasks.

    Pending
  • Roll out graduallyRequired

    Roll out to a small cohort before wider usage.

    Pending
  • Set monitoring and fallback

    Define rollback path and monitor errors after adoption.

    Pending

Evidence readiness

Evidence readiness matrix · balanced

Required evidence gates are covered (5/6 signals complete).

Risk 15

Source provenance

Present

Source repository/provenance is listed.

Required in this preset

Metadata review

Present

Review metadata is present.

Required in this preset

Safety notes

Present

Safety notes are present.

Required in this preset

Privacy notes

Present

Privacy notes are present.

Optional in this preset

Package integrity

Missing

Package integrity metadata is missing.

Optional in this preset

Install payload

Present

Install payload is available.

Required in this preset

Required evidence gates are covered for this preset.

Decision timeline

Decision timeline · balanced

5/6 steps complete with no blocking gaps for this preset.

Risk 14

triage

Confirm source provenanceRequired

Source/provenance metadata is available.

Done

triage

Check metadata review statusRequired

Review metadata is available.

Done

verify

Review safety notesRequired

Safety notes are available.

Done

verify

Review privacy notes

Privacy notes are available.

Done

verify

Validate package integrity metadata

Package integrity metadata is missing.

Pending

rollout

Verify install payload and commandsRequired

Install payload is available.

Done

No required blockers for this timeline preset.

Safety & privacy surface

Safety & privacy surface

1 safety and 1 privacy notes across 2 risk areas. Review closely: credentials & tokens, permissions & scopes.

2 areas
  • SafetyPermissions & scopesRuns automatically on its configured Claude Code hook event and executes shell logic that can read, modify, or delete files in your project (and may run builds, installs, or network calls); review the script and scope it to expected paths before enabling.
  • PrivacyCredentials & tokensReceives Claude Code hook input (session metadata, file paths, and tool output) and reads local project files; review what the script logs or forwards to external services and keep credentials out of its output.

Safety notes

  • Runs automatically on its configured Claude Code hook event and executes shell logic that can read, modify, or delete files in your project (and may run builds, installs, or network calls); review the script and scope it to expected paths before enabling.

Privacy notes

  • Receives Claude Code hook input (session metadata, file paths, and tool output) and reads local project files; review what the script logs or forwards to external services and keep credentials out of its output.

Schema details

Install type
cli
Reading time
1 min
Difficulty score
0
Troubleshooting
Yes
Breaking changes
No
Skill and platform metadata
Retrieval sources
https://code.claude.com/docs/en/hooks
Runtime and command metadata
Trigger
PostToolUse
Script language
bash
Script body
#!/usr/bin/env bash

# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')

if [ -z "$FILE_PATH" ]; then
  exit 0
fi

# Check if it's an environment-related file
if [[ "$FILE_PATH" == *.env* ]] || [[ "$FILE_PATH" == *environment* ]] || [[ "$FILE_PATH" == *config* ]] || [[ "$FILE_PATH" == docker-compose.yml ]] || [[ "$FILE_PATH" == docker-compose.yaml ]]; then
  echo "🔧 Environment file detected: $FILE_PATH" >&2
  
  # Initialize validation counters
  ERRORS=0
  WARNINGS=0
  VALIDATIONS=0
  
  # Function to report validation results
  report_issue() {
    local level="$1"
    local message="$2"
    
    if [ "$level" = "ERROR" ]; then
      echo "❌ $message" >&2
      ERRORS=$((ERRORS + 1))
    elif [ "$level" = "WARNING" ]; then
      echo "⚠️ $message" >&2
      WARNINGS=$((WARNINGS + 1))
    elif [ "$level" = "INFO" ]; then
      echo "ℹ️ $message" >&2
    fi
    VALIDATIONS=$((VALIDATIONS + 1))
  }
  
  # Validate environment file if it exists
  if [ -f "$FILE_PATH" ]; then
    echo "🔍 Validating environment configuration..." >&2
    
    # Check for common required variables
    COMMON_REQUIRED_VARS=("NODE_ENV" "PORT")
    
    if [[ "$FILE_PATH" == *.env* ]]; then
      echo "📋 Checking for environment variables in $FILE_PATH" >&2
      
      # Extract variables from the file
      ENV_VARS=$(grep -oE '^[A-Z_][A-Z0-9_]*=' "$FILE_PATH" 2>/dev/null | sed 's/=//' || echo "")
      
      if [ -n "$ENV_VARS" ]; then
        ENV_COUNT=$(echo "$ENV_VARS" | wc -l | xargs)
        echo "📊 Found $ENV_COUNT environment variables" >&2
      fi
      
      # Security validation - check for insecure defaults
      echo "🔒 Performing security validation..." >&2
      
      INSECURE_PATTERNS=(
        "password=admin"
        "password=123"
        "secret=123"
        "api_key=test"
        "token=demo"
        "password=password"
        "secret=secret"
        "key=key"
      )
      
      for pattern in "${INSECURE_PATTERNS[@]}"; do
        if grep -qi "$pattern" "$FILE_PATH" 2>/dev/null; then
          report_issue "ERROR" "Insecure default detected: $pattern"
        fi
      done
      
      # Check for secrets that are too short
      while IFS= read -r line; do
        if [[ "$line" =~ ^([A-Z_]+)=(.+)$ ]]; then
          var_name="${BASH_REMATCH[1]}"
          var_value="${BASH_REMATCH[2]}"
          
          # Remove quotes from value
          var_value=$(echo "$var_value" | sed 's/^["'\'']*//;s/["'\'']*$//')
          
          # Check secret length for security-related variables
          if [[ "$var_name" =~ (SECRET|KEY|TOKEN|PASSWORD) ]]; then
            if [ ${#var_value} -lt 16 ]; then
              report_issue "WARNING" "$var_name is too short (${#var_value} chars), should be at least 16 characters"
            elif [ ${#var_value} -lt 32 ] && [[ "$var_name" =~ (JWT_SECRET|ENCRYPTION_KEY) ]]; then
              report_issue "WARNING" "$var_name should be at least 32 characters for security"
            fi
          fi
          
          # Format validation
          case "$var_name" in
            *PORT*)
              if ! [[ "$var_value" =~ ^[0-9]+$ ]] || [ "$var_value" -le 0 ] || [ "$var_value" -gt 65535 ]; then
                report_issue "ERROR" "$var_name must be a valid port number (1-65535)"
              fi
              ;;
            *URL*|*URI*)
              if ! [[ "$var_value" =~ ^https?:// ]] && ! [[ "$var_value" =~ ^[a-zA-Z][a-zA-Z0-9+.-]*:// ]]; then
                report_issue "WARNING" "$var_name should be a valid URL with protocol"
              fi
              ;;
            *EMAIL*)
              if ! [[ "$var_value" =~ ^[^@]+@[^@]+\.[^@]+$ ]]; then
                report_issue "ERROR" "$var_name must be a valid email address"
              fi
              ;;
            *BOOL*|*ENABLE*|*DEBUG*)
              if ! [[ "$var_value" =~ ^(true|false|1|0|yes|no)$ ]]; then
                report_issue "WARNING" "$var_name should be a boolean value (true/false, 1/0, yes/no)"
              fi
              ;;
          esac
        fi
      done < "$FILE_PATH"
      
      # Environment-specific validation
      if grep -q "NODE_ENV=production" "$FILE_PATH" 2>/dev/null; then
        echo "🏭 Production environment detected - performing production checks" >&2
        
        # Check for development settings in production
        if grep -qi "debug=true" "$FILE_PATH" 2>/dev/null; then
          report_issue "ERROR" "DEBUG should not be enabled in production"
        fi
        
        # Check for required production variables
        PROD_REQUIRED=("JWT_SECRET" "DATABASE_URL")
        for var in "${PROD_REQUIRED[@]}"; do
          if ! grep -q "^$var=" "$FILE_PATH" 2>/dev/null; then
            report_issue "WARNING" "$var is recommended for production environments"
          fi
        done
        
      elif grep -q "NODE_ENV=development" "$FILE_PATH" 2>/dev/null; then
        echo "🔧 Development environment detected" >&2
        
        # Development-specific checks
        if ! grep -q "DEBUG" "$FILE_PATH" 2>/dev/null; then
          report_issue "INFO" "Consider adding DEBUG variable for development"
        fi
      fi
    fi
    
    # Cross-environment consistency check
    echo "🔄 Checking cross-environment consistency..." >&2
    ENV_FILES=(".env" ".env.local" ".env.development" ".env.staging" ".env.production")
    
    EXISTING_ENV_FILES=()
    for env_file in "${ENV_FILES[@]}"; do
      if [ -f "$env_file" ] && [ "$env_file" != "$FILE_PATH" ]; then
        EXISTING_ENV_FILES+=("$env_file")
      fi
    done
    
    if [ ${#EXISTING_ENV_FILES[@]} -gt 0 ]; then
      echo "📂 Found ${#EXISTING_ENV_FILES[@]} other environment files for comparison" >&2
      
      # Extract variable names from current file
      if [[ "$FILE_PATH" == *.env* ]]; then
        CURRENT_VARS=$(grep -oE '^[A-Z_][A-Z0-9_]*=' "$FILE_PATH" 2>/dev/null | sed 's/=//' | sort || echo "")
        
        for other_file in "${EXISTING_ENV_FILES[@]}"; do
          OTHER_VARS=$(grep -oE '^[A-Z_][A-Z0-9_]*=' "$other_file" 2>/dev/null | sed 's/=//' | sort || echo "")
          
          # Find variables in current file but not in other file
          MISSING_IN_OTHER=$(comm -23 <(echo "$CURRENT_VARS") <(echo "$OTHER_VARS") 2>/dev/null || echo "")
          
          if [ -n "$MISSING_IN_OTHER" ] && [ "$MISSING_IN_OTHER" != "" ]; then
            MISSING_COUNT=$(echo "$MISSING_IN_OTHER" | wc -l | xargs)
            if [ "$MISSING_COUNT" -gt 0 ]; then
              report_issue "INFO" "$MISSING_COUNT variables in $FILE_PATH not found in $other_file"
            fi
          fi
        done
      fi
    fi
    
    # Check for .env files in version control
    if [ -f ".gitignore" ]; then
      if ! grep -q "\.env" ".gitignore" 2>/dev/null; then
        report_issue "WARNING" "Consider adding .env files to .gitignore to prevent committing secrets"
      fi
    fi
    
  else
    echo "⚠️ Environment file $FILE_PATH not found for validation" >&2
  fi
  
  # Docker compose specific validation
  if [[ "$FILE_PATH" == docker-compose.y*ml ]]; then
    echo "🐳 Docker Compose file detected - checking environment configuration" >&2
    
    if [ -f "$FILE_PATH" ]; then
      # Check for hardcoded secrets in docker-compose
      if grep -q "password:" "$FILE_PATH" 2>/dev/null; then
        report_issue "WARNING" "Consider using environment variables instead of hardcoded passwords"
      fi
      
      # Check for env_file usage
      if grep -q "env_file:" "$FILE_PATH" 2>/dev/null; then
        echo "✅ Good practice: using env_file for environment variables" >&2
      else
        report_issue "INFO" "Consider using env_file for better environment variable management"
      fi
    fi
  fi
  
  # Summary report
  echo "" >&2
  echo "📋 Validation Summary:" >&2
  echo "  🔍 Validations performed: $VALIDATIONS" >&2
  echo "  ❌ Errors found: $ERRORS" >&2
  echo "  ⚠️ Warnings: $WARNINGS" >&2
  
  if [ "$ERRORS" -eq 0 ] && [ "$WARNINGS" -eq 0 ]; then
    echo "✅ Environment validation passed" >&2
  elif [ "$ERRORS" -eq 0 ]; then
    echo "✅ Environment validation passed with warnings" >&2
  else
    echo "⚠️ Environment validation completed with errors" >&2
  fi
  
  echo "" >&2
  echo "💡 Environment Security Tips:" >&2
  echo "   • Use strong, unique secrets (32+ characters)" >&2
  echo "   • Never commit .env files to version control" >&2
  echo "   • Use different configurations for each environment" >&2
  echo "   • Validate environment variables in CI/CD pipelines" >&2
  
else
  echo "File $FILE_PATH is not an environment configuration file, skipping validation" >&2
fi

exit 0
Full copyable content
{
  "hooks": {
    "postToolUse": {
      "script": "./.claude/hooks/environment-variable-validator.sh",
      "matchers": [
        "write",
        "edit"
      ]
    }
  }
}

About this resource

Features

  • Automatic validation when .env files are modified with real-time validation feedback when environment configuration files are changed during active development
  • Required environment variable checking with cross-environment consistency validation ensuring all required variables are present across different environment files
  • Security validation for insecure defaults and weak secrets with minimum length requirements (16+ characters for secrets, 32+ for JWT/encryption keys) and common insecure pattern detection
  • Format validation for URLs, emails, ports, and booleans with comprehensive type checking including URL protocol validation, email format validation, port range validation (1-65535), and boolean value validation
  • Cross-environment consistency checking comparing .env, .env.local, .env.development, .env.staging, and .env.production files to ensure consistent variable definitions across environments
  • Production vs development environment validation with environment-specific security rules including production security checks (DEBUG disabled, required production variables) and development environment recommendations
  • Configuration schema validation with Docker Compose environment variable validation including env_file usage validation and hardcoded secret detection
  • Comprehensive error reporting and security warnings with detailed validation summaries including error counts, warning counts, and actionable security recommendations

Use Cases

  • Automated environment variable validation during development providing real-time validation feedback when environment configuration files are modified during active development
  • Security auditing of configuration files ensuring environment variables meet security standards with detection of insecure defaults, weak secrets, and hardcoded credentials
  • Cross-environment consistency checking ensuring environment variables are consistently defined across development, staging, and production environments
  • Production deployment safety validation validating production environment configurations before deployment to ensure security and correctness
  • CI/CD pipeline configuration validation automatically validating environment variables in CI/CD pipelines to prevent configuration errors in automated deployments
  • Development workflow integration seamlessly integrating environment variable validation into development workflows without manual intervention or separate validation steps

Installation

  1. Create hooks directory: mkdir -p .claude/hooks
  2. Create hook file: touch .claude/hooks/environment-variable-validator.sh
  3. Make executable: chmod +x .claude/hooks/environment-variable-validator.sh
  4. Add configuration from Hook Configuration section above to .claude/settings.json or ~/.claude/settings.json
  5. Alternative: Use the interactive /hooks command in Claude Code

Config paths

  • Local (not committed): .claude/settings.local.json
  • User settings (global): ~/.claude/settings.json
  • Project-wide (committed): .claude/settings.json

Requirements

  • Claude Code CLI installed
  • Project directory initialized
  • Bash shell available
  • jq JSON processor for parsing hook input (optional but recommended)
  • Git repository (optional, for .gitignore validation)
  • Standard Unix utilities: grep, awk, sed (for parsing .env files, docker-compose.yml, and configuration files) and file system read access for environment variable files

Hook Configuration

{
  "hooks": {
    "postToolUse": {
      "script": "./.claude/hooks/environment-variable-validator.sh",
      "matchers": ["write", "edit"]
    }
  }
}

Hook Script

#!/usr/bin/env bash

# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')

if [ -z "$FILE_PATH" ]; then
  exit 0
fi

# Check if it's an environment-related file
if [[ "$FILE_PATH" == *.env* ]] || [[ "$FILE_PATH" == *environment* ]] || [[ "$FILE_PATH" == *config* ]] || [[ "$FILE_PATH" == docker-compose.yml ]] || [[ "$FILE_PATH" == docker-compose.yaml ]]; then
  echo "🔧 Environment file detected: $FILE_PATH" >&2

  # Initialize validation counters
  ERRORS=0
  WARNINGS=0
  VALIDATIONS=0

  # Function to report validation results
  report_issue() {
    local level="$1"
    local message="$2"

    if [ "$level" = "ERROR" ]; then
      echo "❌ $message" >&2
      ERRORS=$((ERRORS + 1))
    elif [ "$level" = "WARNING" ]; then
      echo "⚠️ $message" >&2
      WARNINGS=$((WARNINGS + 1))
    elif [ "$level" = "INFO" ]; then
      echo "ℹ️ $message" >&2
    fi
    VALIDATIONS=$((VALIDATIONS + 1))
  }

  # Validate environment file if it exists
  if [ -f "$FILE_PATH" ]; then
    echo "🔍 Validating environment configuration..." >&2

    # Check for common required variables
    COMMON_REQUIRED_VARS=("NODE_ENV" "PORT")

    if [[ "$FILE_PATH" == *.env* ]]; then
      echo "📋 Checking for environment variables in $FILE_PATH" >&2

      # Extract variables from the file
      ENV_VARS=$(grep -oE '^[A-Z_][A-Z0-9_]*=' "$FILE_PATH" 2>/dev/null | sed 's/=//' || echo "")

      if [ -n "$ENV_VARS" ]; then
        ENV_COUNT=$(echo "$ENV_VARS" | wc -l | xargs)
        echo "📊 Found $ENV_COUNT environment variables" >&2
      fi

      # Security validation - check for insecure defaults
      echo "🔒 Performing security validation..." >&2

      INSECURE_PATTERNS=(
        "password=admin"
        "password=123"
        "secret=123"
        "api_key=test"
        "token=demo"
        "password=password"
        "secret=secret"
        "key=key"
      )

      for pattern in "${INSECURE_PATTERNS[@]}"; do
        if grep -qi "$pattern" "$FILE_PATH" 2>/dev/null; then
          report_issue "ERROR" "Insecure default detected: $pattern"
        fi
      done

      # Check for secrets that are too short
      while IFS= read -r line; do
        if [[ "$line" =~ ^([A-Z_]+)=(.+)$ ]]; then
          var_name="${BASH_REMATCH[1]}"
          var_value="${BASH_REMATCH[2]}"

          # Remove quotes from value
          var_value=$(echo "$var_value" | sed 's/^["'\'']*//;s/["'\'']*$//')

          # Check secret length for security-related variables
          if [[ "$var_name" =~ (SECRET|KEY|TOKEN|PASSWORD) ]]; then
            if [ ${#var_value} -lt 16 ]; then
              report_issue "WARNING" "$var_name is too short (${#var_value} chars), should be at least 16 characters"
            elif [ ${#var_value} -lt 32 ] && [[ "$var_name" =~ (JWT_SECRET|ENCRYPTION_KEY) ]]; then
              report_issue "WARNING" "$var_name should be at least 32 characters for security"
            fi
          fi

          # Format validation
          case "$var_name" in
            *PORT*)
              if ! [[ "$var_value" =~ ^[0-9]+$ ]] || [ "$var_value" -le 0 ] || [ "$var_value" -gt 65535 ]; then
                report_issue "ERROR" "$var_name must be a valid port number (1-65535)"
              fi
              ;;
            *URL*|*URI*)
              if ! [[ "$var_value" =~ ^https?:// ]] && ! [[ "$var_value" =~ ^[a-zA-Z][a-zA-Z0-9+.-]*:// ]]; then
                report_issue "WARNING" "$var_name should be a valid URL with protocol"
              fi
              ;;
            *EMAIL*)
              if ! [[ "$var_value" =~ ^[^@]+@[^@]+\.[^@]+$ ]]; then
                report_issue "ERROR" "$var_name must be a valid email address"
              fi
              ;;
            *BOOL*|*ENABLE*|*DEBUG*)
              if ! [[ "$var_value" =~ ^(true|false|1|0|yes|no)$ ]]; then
                report_issue "WARNING" "$var_name should be a boolean value (true/false, 1/0, yes/no)"
              fi
              ;;
          esac
        fi
      done < "$FILE_PATH"

      # Environment-specific validation
      if grep -q "NODE_ENV=production" "$FILE_PATH" 2>/dev/null; then
        echo "🏭 Production environment detected - performing production checks" >&2

        # Check for development settings in production
        if grep -qi "debug=true" "$FILE_PATH" 2>/dev/null; then
          report_issue "ERROR" "DEBUG should not be enabled in production"
        fi

        # Check for required production variables
        PROD_REQUIRED=("JWT_SECRET" "DATABASE_URL")
        for var in "${PROD_REQUIRED[@]}"; do
          if ! grep -q "^$var=" "$FILE_PATH" 2>/dev/null; then
            report_issue "WARNING" "$var is recommended for production environments"
          fi
        done

      elif grep -q "NODE_ENV=development" "$FILE_PATH" 2>/dev/null; then
        echo "🔧 Development environment detected" >&2

        # Development-specific checks
        if ! grep -q "DEBUG" "$FILE_PATH" 2>/dev/null; then
          report_issue "INFO" "Consider adding DEBUG variable for development"
        fi
      fi
    fi

    # Cross-environment consistency check
    echo "🔄 Checking cross-environment consistency..." >&2
    ENV_FILES=(".env" ".env.local" ".env.development" ".env.staging" ".env.production")

    EXISTING_ENV_FILES=()
    for env_file in "${ENV_FILES[@]}"; do
      if [ -f "$env_file" ] && [ "$env_file" != "$FILE_PATH" ]; then
        EXISTING_ENV_FILES+=("$env_file")
      fi
    done

    if [ ${#EXISTING_ENV_FILES[@]} -gt 0 ]; then
      echo "📂 Found ${#EXISTING_ENV_FILES[@]} other environment files for comparison" >&2

      # Extract variable names from current file
      if [[ "$FILE_PATH" == *.env* ]]; then
        CURRENT_VARS=$(grep -oE '^[A-Z_][A-Z0-9_]*=' "$FILE_PATH" 2>/dev/null | sed 's/=//' | sort || echo "")

        for other_file in "${EXISTING_ENV_FILES[@]}"; do
          OTHER_VARS=$(grep -oE '^[A-Z_][A-Z0-9_]*=' "$other_file" 2>/dev/null | sed 's/=//' | sort || echo "")

          # Find variables in current file but not in other file
          MISSING_IN_OTHER=$(comm -23 <(echo "$CURRENT_VARS") <(echo "$OTHER_VARS") 2>/dev/null || echo "")

          if [ -n "$MISSING_IN_OTHER" ] && [ "$MISSING_IN_OTHER" != "" ]; then
            MISSING_COUNT=$(echo "$MISSING_IN_OTHER" | wc -l | xargs)
            if [ "$MISSING_COUNT" -gt 0 ]; then
              report_issue "INFO" "$MISSING_COUNT variables in $FILE_PATH not found in $other_file"
            fi
          fi
        done
      fi
    fi

    # Check for .env files in version control
    if [ -f ".gitignore" ]; then
      if ! grep -q "\.env" ".gitignore" 2>/dev/null; then
        report_issue "WARNING" "Consider adding .env files to .gitignore to prevent committing secrets"
      fi
    fi

  else
    echo "⚠️ Environment file $FILE_PATH not found for validation" >&2
  fi

  # Docker compose specific validation
  if [[ "$FILE_PATH" == docker-compose.y*ml ]]; then
    echo "🐳 Docker Compose file detected - checking environment configuration" >&2

    if [ -f "$FILE_PATH" ]; then
      # Check for hardcoded secrets in docker-compose
      if grep -q "password:" "$FILE_PATH" 2>/dev/null; then
        report_issue "WARNING" "Consider using environment variables instead of hardcoded passwords"
      fi

      # Check for env_file usage
      if grep -q "env_file:" "$FILE_PATH" 2>/dev/null; then
        echo "✅ Good practice: using env_file for environment variables" >&2
      else
        report_issue "INFO" "Consider using env_file for better environment variable management"
      fi
    fi
  fi

  # Summary report
  echo "" >&2
  echo "📋 Validation Summary:" >&2
  echo "  🔍 Validations performed: $VALIDATIONS" >&2
  echo "  ❌ Errors found: $ERRORS" >&2
  echo "  ⚠️ Warnings: $WARNINGS" >&2

  if [ "$ERRORS" -eq 0 ] && [ "$WARNINGS" -eq 0 ]; then
    echo "✅ Environment validation passed" >&2
  elif [ "$ERRORS" -eq 0 ]; then
    echo "✅ Environment validation passed with warnings" >&2
  else
    echo "⚠️ Environment validation completed with errors" >&2
  fi

  echo "" >&2
  echo "💡 Environment Security Tips:" >&2
  echo "   • Use strong, unique secrets (32+ characters)" >&2
  echo "   • Never commit .env files to version control" >&2
  echo "   • Use different configurations for each environment" >&2
  echo "   • Validate environment variables in CI/CD pipelines" >&2

else
  echo "File $FILE_PATH is not an environment configuration file, skipping validation" >&2
fi

exit 0

Examples

Environment Variable Validator Hook Script

Complete hook script that performs environment variable validation when configuration files are modified

#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
if [ -z "$FILE_PATH" ]; then
  exit 0
fi
if [[ "$FILE_PATH" == *.env* ]]; then
  echo "Validating environment file: $FILE_PATH" >&2
  ERRORS=0
  WARNINGS=0
  if [ -f "$FILE_PATH" ]; then
    if grep -qi "password=admin" "$FILE_PATH" 2>/dev/null; then
      echo "ERROR: Insecure default password detected" >&2
      ERRORS=$((ERRORS + 1))
    fi
    while IFS= read -r line; do
      if [[ "$line" =~ ^([A-Z_]+)=(.+)$ ]]; then
        var_name="${BASH_REMATCH[1]}"
        var_value="${BASH_REMATCH[2]}"
        if [[ "$var_name" =~ (SECRET|KEY|TOKEN|PASSWORD) ]]; then
          if [ ${#var_value} -lt 16 ]; then
            echo "WARNING: $var_name is too short (${#var_value} chars)" >&2
            WARNINGS=$((WARNINGS + 1))
          fi
        fi
      fi
    done < "$FILE_PATH"
  fi
  echo "Validation completed: $ERRORS errors, $WARNINGS warnings" >&2
fi
exit 0

Hook Configuration

Complete hook configuration for .claude/settings.json to enable environment variable validation

{
  "hooks": {
    "postToolUse": {
      "script": "./.claude/hooks/environment-variable-validator.sh",
      "matchers": ["write", "edit"]
    }
  }
}

Production Environment Validation

Enhanced hook script for production environment validation with security checks

#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
if [[ "$FILE_PATH" == *.env* ]]; then
  if [ -f "$FILE_PATH" ]; then
    if grep -q "NODE_ENV=production" "$FILE_PATH" 2>/dev/null; then
      echo "Production environment detected - performing production checks" >&2
      if grep -qi "debug=true" "$FILE_PATH" 2>/dev/null; then
        echo "ERROR: DEBUG should not be enabled in production" >&2
      fi
      PROD_REQUIRED=("JWT_SECRET" "DATABASE_URL")
      for var in "${PROD_REQUIRED[@]}"; do
        if ! grep -q "^$var=" "$FILE_PATH" 2>/dev/null; then
          echo "WARNING: $var is recommended for production environments" >&2
        fi
      done
    fi
  fi
fi
exit 0

Format Validation for Environment Variables

Enhanced hook script for format validation of URLs, emails, ports, and other environment variable types

#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
if [[ "$FILE_PATH" == *.env* ]]; then
  if [ -f "$FILE_PATH" ]; then
    while IFS= read -r line; do
      if [[ "$line" =~ ^([A-Z_]+)=(.+)$ ]]; then
        var_name="${BASH_REMATCH[1]}"
        var_value="${BASH_REMATCH[2]}"
        case "$var_name" in
          *PORT*)
            if ! [[ "$var_value" =~ ^[0-9]+$ ]] || [ "$var_value" -le 0 ] || [ "$var_value" -gt 65535 ]; then
              echo "ERROR: $var_name must be a valid port number (1-65535)" >&2
            fi
            ;;
          *URL*|*URI*)
            if ! [[ "$var_value" =~ ^https?:// ]]; then
              echo "WARNING: $var_name should be a valid URL with protocol" >&2
            fi
            ;;
          *EMAIL*)
            if ! [[ "$var_value" =~ ^[^@]+@[^@]+\.[^@]+$ ]]; then
              echo "ERROR: $var_name must be a valid email address" >&2
            fi
            ;;
        esac
      fi
    done < "$FILE_PATH"
  fi
fi
exit 0

Security Best Practices Validation

Enhanced hook script for security best practices validation including .gitignore checks and Docker Compose security

#!/usr/bin/env bash
if [ -f ".gitignore" ]; then
  if ! grep -q "\.env" ".gitignore" 2>/dev/null; then
    echo "WARNING: Consider adding .env files to .gitignore to prevent committing secrets" >&2
  fi
fi
if [[ "$FILE_PATH" == docker-compose.y*ml ]]; then
  if [ -f "$FILE_PATH" ]; then
    if grep -q "password:" "$FILE_PATH" 2>/dev/null; then
      echo "WARNING: Consider using environment variables instead of hardcoded passwords" >&2
    fi
    if grep -q "env_file:" "$FILE_PATH" 2>/dev/null; then
      echo "Good practice: using env_file for environment variables" >&2
    fi
  fi
fi
exit 0

Troubleshooting

Hook triggers on every file write, slowing development

Narrow matchers to specific .env files only: matchers: ['write:.env*', 'edit:.env*'] in hookConfig to reduce unnecessary validations and improve performance. Use targeted file patterns to exclude non-environment files. Consider using file size thresholds to skip small files.

False positives for weak secrets in development environments

Add NODE_ENV check in script to skip strict secret length validation for development. Use conditional logic: if NODE_ENV != production, bypass warnings. Create separate validation rules for development vs production environments. Use environment-specific validation thresholds.

Hook fails to detect environment files in nested directories

Update file path matching regex to include subdirectories: [["$FILE_PATH" == /.env]] and find .env files recursively for comprehensive validation. Use find command to locate all .env files in project. Consider validating all environment files in project directory tree.

Cross-environment comparison reports too many false differences

Filter comparison to only critical variables (DB, API keys, secrets). Exclude dev-only vars like DEBUG or LOCAL_DEV_PORT from consistency checks to reduce noise. Use whitelist of important variables for cross-environment comparison. Configure variable exclusion patterns.

Script exits with errors preventing file saves entirely

Change validation errors to warnings with exit 0 instead of exit 1. Log issues to stderr for review but allow operations to complete without blocking development. Use non-blocking validation that reports issues without preventing file operations. Consider using validation levels (error, warning, info).

Format validation fails for environment variables with special characters

Use proper quoting and escaping for environment variable values. Handle special characters in variable values with proper escaping. Verify regex patterns handle escaped characters correctly. Test validation with complex environment variable values including special characters.

Docker Compose validation doesn't detect environment variables in service definitions

Parse Docker Compose YAML structure to extract environment variables from services. Use yq or similar YAML parser for Docker Compose files. Check both 'environment' and 'env_file' sections in Docker Compose. Validate environment variables in all service definitions.

Validation doesn't check for required variables based on project type

Detect project type (Node.js, Python, etc.) and validate project-specific required variables. Check for package.json, requirements.txt, or other project files to determine required environment variables. Use project-specific validation rules based on detected project type. Create validation profiles for different project types.

Source citations

Add this badge to your README

Show that Environment Validator is listed on HeyClaude. Paste this Markdown into your README — it renders the badge and links back to this page.

Listed on HeyClaude
[![Listed on HeyClaude](https://heyclau.de/badge/hooks/environment-variable-validator.svg)](https://heyclau.de/entry/hooks/environment-variable-validator)

How it compares

Environment Validator side by side with 3 alternatives on trust, install, platform support, and disclosed safety notes — all from reviewed registry metadata.

Field

Validates environment variables, checks for required vars, and ensures proper configuration across environments.

Open dossier

Validates AWS CloudFormation templates for syntax errors and best practices using cfn-lint v1.40.4+ and AWS CLI v2.27.54+.

Open dossier

Validates GraphQL schema files and checks for breaking changes when modified.

Open dossier

Validates translation files for missing keys and ensures consistency across different language files.

Open dossier
Next steps
Trust
Review statusReviewedMaintainer reviewedReviewedMaintainer reviewedReviewedMaintainer reviewedReviewedMaintainer reviewed
Package trustPackage not verifiedPackage not verifiedPackage not verifiedPackage not verified
Source provenanceSource-backedSource-backedSource-backedSource-backed
Submitter
Install riskReview firstReview firstReview firstReview first
Notes Safety Privacy Safety Privacy Safety Privacy Safety Privacy
BrandAWS logoAWS
Categoryhookshookshookshooks
Sourcesource-backedsource-backedsource-backedsource-backed
AuthorJSONboredJSONboredJSONboredJSONbored
Added2025-09-162025-09-192025-09-192025-09-19
Platforms
Claude Code
Claude Code
Claude Code
Claude Code
Source repo
Safety notesRuns automatically on its configured Claude Code hook event and executes shell logic that can read, modify, or delete files in your project (and may run builds, installs, or network calls); review the script and scope it to expected paths before enabling.Runs automatically on its configured Claude Code hook event and executes shell logic that can read, modify, or delete files in your project (and may run builds, installs, or network calls); review the script and scope it to expected paths before enabling.Runs automatically on its configured Claude Code hook event and executes shell logic that can read, modify, or delete files in your project (and may run builds, installs, or network calls); review the script and scope it to expected paths before enabling.Runs automatically on its configured Claude Code hook event and executes shell logic that can read, modify, or delete files in your project (and may run builds, installs, or network calls); review the script and scope it to expected paths before enabling.
Privacy notesReceives Claude Code hook input (session metadata, file paths, and tool output) and reads local project files; review what the script logs or forwards to external services and keep credentials out of its output.Receives Claude Code hook input (session metadata, file paths, and tool output) and reads local project files; review what the script logs or forwards to external services and keep credentials out of its output.Receives Claude Code hook input (session metadata, file paths, and tool output) and reads local project files; review what the script logs or forwards to external services and keep credentials out of its output.Receives Claude Code hook input (session metadata, file paths, and tool output) and reads local project files; review what the script logs or forwards to external services and keep credentials out of its output.
Prerequisites— none listed— none listed— none listed— none listed
Install
mkdir -p .claude/hooks && touch .claude/hooks/environment-variable-validator.sh && chmod +x .claude/hooks/environment-variable-validator.sh
mkdir -p .claude/hooks && touch .claude/hooks/aws-cloudformation-validator.sh && chmod +x .claude/hooks/aws-cloudformation-validator.sh
mkdir -p .claude/hooks && touch .claude/hooks/graphql-schema-validator.sh && chmod +x .claude/hooks/graphql-schema-validator.sh
mkdir -p .claude/hooks && touch .claude/hooks/i18n-translation-validator.sh && chmod +x .claude/hooks/i18n-translation-validator.sh
Config
{
  "hooks": {
    "postToolUse": {
      "script": "./.claude/hooks/environment-variable-validator.sh",
      "matchers": [
        "write",
        "edit"
      ]
    }
  }
}
{
  "hooks": {
    "postToolUse": {
      "script": "./.claude/hooks/aws-cloudformation-validator.sh",
      "matchers": [
        "write",
        "edit"
      ]
    }
  }
}
{
  "hooks": {
    "postToolUse": {
      "script": "./.claude/hooks/graphql-schema-validator.sh",
      "matchers": [
        "write",
        "edit"
      ]
    }
  }
}
{
  "hooks": {
    "postToolUse": {
      "script": "./.claude/hooks/i18n-translation-validator.sh",
      "matchers": [
        "write",
        "edit"
      ]
    }
  }
}
Citations
ClaimUnclaimedUnclaimedUnclaimedUnclaimed
Open 4 picks in the interactive comparison tool

Related guides

Signals

Loading live community signals…

More like this, weekly

A short, calm digest of reviewed Claude resources. Unsubscribe any time.