Skip to main content

Overview

Envark’s risk analysis engine evaluates environment variables for security vulnerabilities, configuration issues, and best practice violations. It uses a multi-factor scoring system to classify risks and provides actionable recommendations.

Risk Levels

Envark classifies issues into five severity levels:

Critical

Score: 5Immediate security threats or application-breaking issues:
  • Variables used in code with no definition
  • Hardcoded secrets in committed files
  • Exposed credentials

High

Score: 4Serious security risks requiring urgent attention:
  • Secrets in potentially committed .env files
  • Weak encryption keys
  • Missing required variables with no defaults

Medium

Score: 3Configuration issues that should be addressed:
  • Variables with conflicting values across files
  • Multiple usages with no default value
  • Placeholder values in production
  • Inconsistent naming patterns

Low

Score: 1-2Minor issues and improvements:
  • Undocumented variables
  • Dead variables (defined but unused)
  • Empty values
  • Poor naming conventions

Info

Score: 0Informational findings with no risk:
  • Well-configured variables
  • Properly documented settings
  • Following best practices

Risk Scoring Algorithm

Envark calculates a risk score (0-5) using multiple factors:
// From src/core/analyzer.ts:99-129
function calculateRiskScore(variable: EnvVariable): number {
    let score = 0;

    // Critical: Used but never defined anywhere and no default
    if (variable.usedInCode && !variable.definedInEnvFile && !variable.hasDefault) {
        score += 5;
    }

    // High: Defined in .env but not in .env.example (potential secret leak)
    if (variable.definedInEnvFile && !variable.definedInExample && looksLikeSecret(variable.name)) {
        score += 4;
    }

    // Medium: Used in multiple files with no default
    if (variable.usedInCode && variable.usages.length > 2 && !variable.hasDefault) {
        score += 3;
    }

    // Low: Not documented
    if (!variable.isDocumented && variable.usedInCode) {
        score += 1;
    }

    // Low: Dead variable (defined but never used)
    if (variable.definedInEnvFile && !variable.usedInCode) {
        score += 1;
    }

    return Math.min(score, 5);
}

Score to Risk Level Mapping

// From src/core/analyzer.ts:134-140
function scoreToRiskLevel(score: number): RiskLevel {
    if (score >= 5) return 'critical';
    if (score >= 4) return 'high';
    if (score >= 3) return 'medium';
    if (score >= 1) return 'low';
    return 'info';
}

Issue Types

Envark detects nine distinct issue types:
Severity: CriticalVariable is used in code but not defined anywhere.
// code.ts
const apiKey = process.env.API_KEY;  // ✗ API_KEY not in any .env file
Risk: Application will receive undefined, potentially causing runtime errors or security issues.Recommendation: Add the variable to your .env file or provide a default value in code.
# .env
API_KEY=your_api_key_here

Secret Detection

Envark uses pattern matching to identify potential secrets:
// From src/core/analyzer.ts:50-60
const SECRET_PATTERNS = [
    /SECRET/i,
    /PASSWORD/i,
    /PASS$/i,
    /TOKEN/i,
    /KEY$/i,
    /API_KEY/i,
    /PRIVATE/i,
    /CREDENTIAL/i,
    /AUTH/i,
];

function looksLikeSecret(name: string): boolean {
    return SECRET_PATTERNS.some(pattern => pattern.test(name));
}

Detected Secret Patterns

API Keys

  • API_KEY
  • OPENAI_KEY
  • STRIPE_KEY
  • GOOGLE_API_KEY

Passwords

  • PASSWORD
  • DB_PASSWORD
  • ADMIN_PASS
  • USER_PASSWORD

Tokens

  • ACCESS_TOKEN
  • JWT_TOKEN
  • REFRESH_TOKEN
  • AUTH_TOKEN

Secrets

  • SECRET
  • JWT_SECRET
  • SESSION_SECRET
  • WEBHOOK_SECRET

Private Keys

  • PRIVATE_KEY
  • SSH_KEY
  • SIGNING_KEY
  • ENCRYPTION_KEY

Credentials

  • CREDENTIALS
  • AWS_CREDENTIALS
  • DB_CREDENTIALS
  • AUTH_CREDENTIALS

Running Risk Analysis

CLI Command

# Analyze all variables
envark risk

# Filter by minimum risk level
envark risk --min-level high
envark risk --min-level critical

TUI Command

# In interactive mode
/risk
r

Output Format

┌─ RISK ANALYSIS ───────────────────────────────────────────┐
│  Critical: 2  High: 5  Medium: 12  Low: 23
└──────────────────────────────────────────────────────────┘

  ⚠ DATABASE_PASSWORD [CRITICAL]
    → Used in code but not defined in any .env file
    → Add DATABASE_PASSWORD to your .env file or provide a default value

  ⚠ SECRET_KEY [HIGH]
    → Looks like a secret but is in a potentially committed .env file
    → Move SECRET_KEY to .env.local or ensure .env is in .gitignore

  ⚠ API_URL [MEDIUM]
    → Has different values across .env files
    → .env: "https://prod.example.com"
    → .env.local: "http://localhost:3000"

Analysis Result Structure

// From src/core/analyzer.ts:34-47
export interface AnalysisResult {
    variables: AnalyzedVariable[];
    summary: {
        totalVariables: number;
        critical: number;
        high: number;
        medium: number;
        low: number;
        info: number;
        byIssueType: Record<IssueType, number>;
    };
    duplicateGroups: Map<string, Array<{ file: string; value: string }>>;
    similarNameGroups: Map<string, string[]>;
}

Recommendations Engine

For each variable, Envark generates contextual recommendations:
// From src/core/analyzer.ts:263-292
function generateRecommendations(variable: EnvVariable, issues: Issue[]): string[] {
    const recommendations: string[] = [];

    // Add unique recommendations from issues
    for (const issue of issues) {
        recommendations.push(issue.recommendation);
    }

    // Add general recommendations
    if (variable.usedInCode && variable.usages.length > 3 && !variable.hasDefault) {
        recommendations.push(
            `Consider creating a config module that validates ${variable.name} at startup`
        );
    }

    if (variable.languages.length > 1) {
        recommendations.push(
            `${variable.name} is used across ${variable.languages.join(', ')} - ensure consistent handling`
        );
    }

    return recommendations;
}

Example Recommendations

  • Add DATABASE_URL to your .env file
  • Provide a default value in code
  • Create a config validation module
  • Document required environment variables
  • Move to .env.local (git-ignored)
  • Use environment-specific files
  • Implement secret rotation
  • Consider using AWS Secrets Manager or HashiCorp Vault
  • Review git history for leaked credentials
  • Standardize to DATABASE_URL across all files
  • Create a naming convention guide
  • Use a linter to enforce patterns
  • Migrate old variable names gradually

Filtering Results

By Risk Level

// From src/core/analyzer.ts:370-377
export function filterByRisk(
    result: AnalysisResult,
    minRisk: RiskLevel
): AnalyzedVariable[] {
    const riskOrder: Record<RiskLevel, number> = { 
        critical: 5, high: 4, medium: 3, low: 2, info: 1 
    };
    const minScore = riskOrder[minRisk];
    return result.variables.filter(v => riskOrder[v.riskLevel] >= minScore);
}

By Issue Type

// From src/core/analyzer.ts:383-387
export function filterByIssueType(
    result: AnalysisResult,
    issueType: IssueType
): AnalyzedVariable[] {
    return result.variables.filter(v => 
        v.issues.some(i => i.type === issueType)
    );
}

AI-Enhanced Analysis

When an AI provider is configured, Envark can provide deeper insights:
# Get AI analysis
envark analyze

# Or in TUI
/analyze
an
The AI considers:
  • Your specific framework (Next.js, Django, etc.)
  • Industry-specific security practices
  • Common vulnerability patterns
  • Best practices for your tech stack

Best Practices

Regular Scanning

Run envark risk regularly, especially before deployments.

Fix Critical First

Address Critical and High issues before Medium and Low.

Document Decisions

If you intentionally ignore an issue, document why in comments.

Use CI/CD Integration

Add Envark to your CI pipeline to catch issues early.

CI/CD Integration

# .github/workflows/env-check.yml
name: Environment Variable Check

on: [push, pull_request]

jobs:
  envark:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install Envark
        run: npm install -g envark
      - name: Run Risk Analysis
        run: envark risk --min-level high --fail-on-issues

Programmatic Usage

import { scanProject } from 'envark';
import { resolveEnvMap } from 'envark/core/resolver';
import { analyzeEnvVariables, filterByRisk } from 'envark/core/analyzer';

const scan = scanProject('/path/to/project');
const resolved = resolveEnvMap(scan.usages);
const analysis = analyzeEnvVariables(resolved);

// Get critical issues
const critical = filterByRisk(analysis, 'critical');

if (critical.length > 0) {
    console.error(`Found ${critical.length} critical issues!`);
    process.exit(1);
}

Implementation Reference

The risk analysis engine is implemented in:
  • src/core/analyzer.ts: Main analysis logic (lines 99-365)
  • src/core/resolver.ts: Variable resolution and deduplication
  • src/tools/get_env_risk.ts: CLI tool interface
See src/core/analyzer.ts:295-365 for the complete analysis algorithm.

Build docs developers (and LLMs) love